From 9c2325ff6b14984d6cc8b2b51d4412c8bd4c7297 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 23 Jul 2016 15:57:04 -0700 Subject: [PATCH] modernize and improve type-safety of the DHT put implementation and test (#929) modernize and improve type-safety of the DHT put implementation and tests. use unique_ptr instead of malloc for dht put items. --- Jamfile | 2 + bindings/python/src/session.cpp | 22 +- include/libtorrent/Makefile.am | 1 + include/libtorrent/bdecode.hpp | 5 +- include/libtorrent/ed25519.hpp | 2 + include/libtorrent/hex.hpp | 3 + include/libtorrent/kademlia/dht_storage.hpp | 18 +- include/libtorrent/kademlia/dht_tracker.hpp | 4 +- include/libtorrent/kademlia/find_data.hpp | 2 +- include/libtorrent/kademlia/get_item.hpp | 10 +- include/libtorrent/kademlia/item.hpp | 97 +++---- include/libtorrent/kademlia/msg.hpp | 1 + include/libtorrent/kademlia/node.hpp | 8 +- include/libtorrent/kademlia/types.hpp | 96 +++++++ include/libtorrent/session_handle.hpp | 2 +- include/libtorrent/stack_allocator.hpp | 1 + simulation/test_dht.cpp | 22 +- simulation/test_dht_storage.cpp | 19 +- src/alert.cpp | 6 +- src/bdecode.cpp | 6 +- src/bt_peer_connection.cpp | 38 +-- src/create_torrent.cpp | 2 +- src/kademlia/dht_storage.cpp | 143 ++++----- src/kademlia/dht_tracker.cpp | 7 +- src/kademlia/get_item.cpp | 51 ++-- src/kademlia/item.cpp | 209 +++++++------- src/kademlia/node.cpp | 99 +++---- src/kademlia/put_data.cpp | 6 +- src/pe_crypto.cpp | 8 +- src/read_resume_data.cpp | 3 +- src/session_handle.cpp | 2 + src/session_impl.cpp | 54 ++-- src/smart_ban.cpp | 4 +- src/torrent.cpp | 8 +- src/torrent_info.cpp | 19 +- test/Jamfile | 2 +- test/test_bdecode.cpp | 88 +++--- test/test_dht.cpp | 303 ++++++++++---------- test/test_dht_storage.cpp | 51 ++-- test/test_direct_dht.cpp | 4 +- tools/dht_put.cpp | 35 +-- 41 files changed, 781 insertions(+), 682 deletions(-) create mode 100644 include/libtorrent/kademlia/types.hpp diff --git a/Jamfile b/Jamfile index 6dfccb12c..81371c342 100644 --- a/Jamfile +++ b/Jamfile @@ -297,6 +297,8 @@ rule warnings ( properties * ) result += /wd4251 ; # disable warning C4275: non DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' result += /wd4275 ; +# disable warning C4373: virtual function overrides, previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers + result += /wd4373 ; } return $(result) ; diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 6292020d5..f4907b92b 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -457,9 +457,9 @@ namespace ses.dht_get_item(public_key, salt); } - void put_string(entry& e, std::array& sig, std::uint64_t& seq, - std::string const& salt, std::string public_key, std::string private_key, - std::string data) + void put_string(entry& e, std::array& sig, std::uint64_t& seq + , std::string const& salt, std::string pk, std::string sk + , std::string data) { using libtorrent::dht::sign_mutable_item; @@ -467,21 +467,25 @@ namespace std::vector buf; bencode(std::back_inserter(buf), e); ++seq; - sign_mutable_item(std::pair(&buf[0], int(buf.size())) - , std::pair(&salt[0], int(salt.size())) - , seq, public_key.c_str(), private_key.c_str(), sig.data()); + dht::signature sign; + sign_mutable_item(buf, salt + , dht::sequence_number(seq) + , dht::public_key(pk.data()) + , dht::secret_key(sk.data()) + , sign); + sig = sign.bytes; } void dht_put_mutable_item(lt::session& ses, std::string private_key, std::string public_key, - std::string data, std::string salt) + std::string data, std::string salt) { TORRENT_ASSERT(private_key.size() == 64); TORRENT_ASSERT(public_key.size() == 32); std::array key; std::copy(public_key.begin(), public_key.end(), key.begin()); ses.dht_put_item(key, boost::bind(&put_string, _1, _2, _3, _4 - , public_key, private_key, data) - , salt); + , public_key, private_key, data) + , salt); } #endif diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 815df0641..7454e9594 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -194,6 +194,7 @@ nobase_include_HEADERS = \ kademlia/routing_table.hpp \ kademlia/rpc_manager.hpp \ kademlia/traversal_algorithm.hpp \ + kademlia/types.hpp \ kademlia/item.hpp \ kademlia/get_item.hpp \ kademlia/get_peers.hpp diff --git a/include/libtorrent/bdecode.hpp b/include/libtorrent/bdecode.hpp index 0a1700144..b09fab155 100644 --- a/include/libtorrent/bdecode.hpp +++ b/include/libtorrent/bdecode.hpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/disable_warnings_pop.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/span.hpp" /* @@ -238,6 +239,8 @@ struct bdecode_token // There are 5 different types of nodes, see type_t. struct TORRENT_EXPORT bdecode_node { + // TODO: 3 make this take span for buffer, and make it return a + // bdecode_node TORRENT_EXPORT friend int bdecode(char const* start, char const* end, bdecode_node& ret , error_code& ec, int* error_pos, int depth_limit , int token_limit); @@ -280,7 +283,7 @@ struct TORRENT_EXPORT bdecode_node // buffer where this node is defined. For a dictionary for instance, this // starts with ``d`` and ends with ``e``, and has all the content of the // dictionary in between. - std::pair data_section() const; + span 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 diff --git a/include/libtorrent/ed25519.hpp b/include/libtorrent/ed25519.hpp index bb343ccd0..3a85fb74a 100644 --- a/include/libtorrent/ed25519.hpp +++ b/include/libtorrent/ed25519.hpp @@ -20,6 +20,8 @@ extern "C" { void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed); #endif +// TODO: 3 wrap these into C++ calls with proper types (dht::signature, +// public_key and secret_key) void TORRENT_EXPORT ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed); void TORRENT_EXPORT ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key); int TORRENT_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key); diff --git a/include/libtorrent/hex.hpp b/include/libtorrent/hex.hpp index 64dae5496..69299178a 100644 --- a/include/libtorrent/hex.hpp +++ b/include/libtorrent/hex.hpp @@ -49,6 +49,7 @@ namespace libtorrent namespace aux { TORRENT_EXTRA_EXPORT int hex_to_int(char in); + // TODO: 3 take an span here instead TORRENT_EXTRA_EXPORT bool is_hex(char const *in, int len); // The overload taking a ``std::string`` converts (binary) the string ``s`` @@ -58,6 +59,7 @@ namespace libtorrent // ``out``. The caller is responsible for making sure the buffer pointed to // by ``out`` is large enough, i.e. has at least len * 2 bytes of space. TORRENT_DEPRECATED_EXPORT std::string to_hex(std::string const& s); + // TODO: 3 take an span here instead TORRENT_DEPRECATED_EXPORT void to_hex(char const *in, int len, char* out); // converts the buffer [``in``, ``in`` + len) from hexadecimal to @@ -65,6 +67,7 @@ namespace libtorrent // by ``out``. The caller is responsible for making sure the buffer // at ``out`` has enough space for the result to be written to, i.e. // (len + 1) / 2 bytes. + // TODO: 3 take an span here instead TORRENT_DEPRECATED_EXPORT bool from_hex(char const *in, int len, char* out); } diff --git a/include/libtorrent/kademlia/dht_storage.hpp b/include/libtorrent/kademlia/dht_storage.hpp index c89781a02..bdaa672af 100644 --- a/include/libtorrent/kademlia/dht_storage.hpp +++ b/include/libtorrent/kademlia/dht_storage.hpp @@ -40,10 +40,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/disable_warnings_pop.hpp" #include +#include #include #include #include +#include namespace libtorrent { @@ -164,7 +166,7 @@ namespace dht // dht_settings::max_dht_items. // virtual void put_immutable_item(sha1_hash const& target - , char const* buf, int size + , span buf , address const& addr) = 0; // This function retrieves the sequence number of a mutable item. @@ -173,7 +175,7 @@ namespace dht // inside the out parameter seq. // virtual bool get_mutable_item_seq(sha1_hash const& target - , std::int64_t& seq) const = 0; + , sequence_number& seq) const = 0; // This function retrieves the mutable stored in the DHT. // @@ -189,7 +191,7 @@ namespace dht // inside the (entry) out parameter item. // virtual bool get_mutable_item(sha1_hash const& target - , std::int64_t seq, bool force_fill + , sequence_number seq, bool force_fill , entry& item) const = 0; // Store the item's data. This layer is only for storage. @@ -201,11 +203,11 @@ namespace dht // dht_settings::max_dht_items. // virtual void put_mutable_item(sha1_hash const& target - , char const* buf, int size - , char const* sig - , std::int64_t seq - , char const* pk - , char const* salt, int salt_size + , span buf + , signature const& sig + , sequence_number seq + , public_key const& pk + , span salt , address const& addr) = 0; // This function is called periodically (non-constant frequency). diff --git a/include/libtorrent/kademlia/dht_tracker.hpp b/include/libtorrent/kademlia/dht_tracker.hpp index ab5ed4cd6..dadb875a6 100644 --- a/include/libtorrent/kademlia/dht_tracker.hpp +++ b/include/libtorrent/kademlia/dht_tracker.hpp @@ -106,7 +106,7 @@ namespace libtorrent { namespace dht // key is a 32-byte binary string, the public key to look up. // the salt is optional - void get_item(char const* key + void get_item(public_key const& key , boost::function cb , std::string salt = std::string()); @@ -119,7 +119,7 @@ namespace libtorrent { namespace dht // for mutable_item. // the data_cb will be called when we get authoritative mutable_item, // the cb is same as put immutable_item. - void put_item(char const* key + void put_item(public_key const& key , boost::function cb , boost::function data_cb, std::string salt = std::string()); diff --git a/include/libtorrent/kademlia/find_data.hpp b/include/libtorrent/kademlia/find_data.hpp index 9fea0f1dc..62a48e1ec 100644 --- a/include/libtorrent/kademlia/find_data.hpp +++ b/include/libtorrent/kademlia/find_data.hpp @@ -65,7 +65,7 @@ struct find_data : traversal_algorithm { typedef boost::function > const&)> nodes_callback; - find_data(node & node, node_id target + find_data(node& node, node_id target , nodes_callback const& ncallback); void got_write_token(node_id const& n, std::string const& write_token); diff --git a/include/libtorrent/kademlia/get_item.hpp b/include/libtorrent/kademlia/get_item.hpp index f3798b19d..1ae56cfab 100644 --- a/include/libtorrent/kademlia/get_item.hpp +++ b/include/libtorrent/kademlia/get_item.hpp @@ -46,9 +46,9 @@ public: typedef boost::function data_callback; void got_data(bdecode_node const& v, - char const* pk, - std::uint64_t seq, - char const* sig); + public_key const& pk, + sequence_number seq, + signature const& sig); // for immutable itms get_item(node& dht_node @@ -58,8 +58,8 @@ public: // for mutable items get_item(node& dht_node - , char const* pk - , std::string const& salt + , public_key const& pk + , span salt , data_callback const& dcallback , nodes_callback const& ncallback); diff --git a/include/libtorrent/kademlia/item.hpp b/include/libtorrent/kademlia/item.hpp index 7a90e510e..0b3ae7cb4 100644 --- a/include/libtorrent/kademlia/item.hpp +++ b/include/libtorrent/kademlia/item.hpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2013, Steven Siloti +Copyright (c) 2013, Steven Siloti, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -36,6 +36,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include + #include #include #include @@ -44,19 +47,18 @@ namespace libtorrent { namespace dht { // calculate the target hash for an immutable item. -sha1_hash TORRENT_EXTRA_EXPORT item_target_id( - std::pair v); +sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span v); // calculate the target hash for a mutable item. -sha1_hash TORRENT_EXTRA_EXPORT item_target_id(std::pair salt - , char const* pk); +sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span salt + , public_key const& pk); bool TORRENT_EXTRA_EXPORT verify_mutable_item( - std::pair v - , std::pair salt - , std::uint64_t seq - , char const* pk - , char const* sig); + span v + , span salt + , sequence_number seq + , public_key const& pk + , signature const& sig); // TODO: since this is a public function, it should probably be moved // out of this header and into one with other public functions. @@ -68,47 +70,40 @@ bool TORRENT_EXTRA_EXPORT verify_mutable_item( // is responsible for allocating the destination buffer that's passed in // as the ``sig`` argument. Typically it would be allocated on the stack. void TORRENT_EXPORT sign_mutable_item( - std::pair v - , std::pair salt - , std::uint64_t seq - , char const* pk - , char const* sk - , char* sig); - -enum -{ - item_pk_len = 32, - item_sk_len = 64, - item_sig_len = 64 -}; + span v + , span salt + , sequence_number seq + , public_key const& pk + , secret_key const& sk + , signature& sig); class TORRENT_EXTRA_EXPORT item { public: item() : m_seq(0), m_mutable(false) {} - item(char const* pk, std::string const& salt); - item(entry const& v) { assign(v); } - item(entry const& v - , std::pair salt - , std::uint64_t seq, char const* pk, char const* sk); - item(bdecode_node const& v) { assign(v); } + item(public_key const& pk, span salt); + item(entry v); + item(entry v + , span salt + , sequence_number seq + , public_key const& pk + , secret_key const& sk); + item(bdecode_node const& v); - void assign(entry const& v) - { - assign(v, std::pair(static_cast(nullptr) - , 0), 0, nullptr, nullptr); - } - void assign(entry const& v, std::pair salt - , std::uint64_t seq, char const* pk, char const* sk); - void assign(bdecode_node const& v) - { - assign(v, std::pair(static_cast(nullptr) - , 0), 0, nullptr, nullptr); - } - bool assign(bdecode_node const& v, std::pair salt - , std::uint64_t seq, char const* pk, char const* sig); - void assign(entry const& v, std::string salt, std::uint64_t seq - , char const* pk, char const* sig); + void assign(entry v); + void assign(entry v, span salt + , sequence_number seq + , public_key const& pk + , secret_key const& sk); + void assign(bdecode_node const& v); + bool assign(bdecode_node const& v, span salt + , sequence_number seq + , public_key const& pk + , signature const& sig); + void assign(entry v, span salt + , sequence_number seq + , public_key const& pk + , signature const& sig); void clear() { m_value = entry(); } bool empty() const { return m_value.type() == entry::undefined_t; } @@ -116,19 +111,19 @@ public: bool is_mutable() const { return m_mutable; } entry const& value() const { return m_value; } - std::array const& pk() const + public_key const& pk() const { return m_pk; } - std::array const& sig() const + signature const& sig() const { return m_sig; } - std::uint64_t seq() const { return m_seq; } + sequence_number seq() const { return m_seq; } std::string const& salt() const { return m_salt; } private: entry m_value; std::string m_salt; - std::array m_pk; - std::array m_sig; - std::uint64_t m_seq; + public_key m_pk; + signature m_sig; + sequence_number m_seq; bool m_mutable; }; diff --git a/include/libtorrent/kademlia/msg.hpp b/include/libtorrent/kademlia/msg.hpp index caa015cac..c2ba86b57 100644 --- a/include/libtorrent/kademlia/msg.hpp +++ b/include/libtorrent/kademlia/msg.hpp @@ -93,6 +93,7 @@ void incoming_error(entry& e, char const* msg, int error_code = 203); // given a redundant name to avoid clashing with libtorrent::detail namespace dht_detail { +//#error move this to its own .hpp/.cpp pair and make it take an span instead of being a template TORRENT_EXPORT bool verify_message(bdecode_node const& msg, key_desc_t const desc[] , bdecode_node ret[], int size, char* error, int error_size); diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index 1c0d32609..3e7eb43c1 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -150,17 +150,17 @@ public: , boost::function f); void get_item(sha1_hash const& target, boost::function f); - void get_item(char const* pk, std::string const& salt, boost::function f); + void get_item(public_key const& pk, std::string const& salt, boost::function f); void put_item(sha1_hash const& target, entry const& data, boost::function f); - void put_item(char const* pk, std::string const& salt + void put_item(public_key const& pk, std::string const& salt , boost::function f , boost::function data_cb); - bool verify_token(std::string const& token, char const* info_hash + bool verify_token(std::string const& token, sha1_hash const& info_hash , udp::endpoint const& addr) const; - std::string generate_token(udp::endpoint const& addr, char const* info_hash); + std::string generate_token(udp::endpoint const& addr, sha1_hash const& info_hash); // the returned time is the delay until connection_timeout() // should be called again the next time diff --git a/include/libtorrent/kademlia/types.hpp b/include/libtorrent/kademlia/types.hpp new file mode 100644 index 000000000..d3dbf1b62 --- /dev/null +++ b/include/libtorrent/kademlia/types.hpp @@ -0,0 +1,96 @@ +/* + +Copyright (c) 2016, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef LIBTORRENT_TYPES_HPP +#define LIBTORRENT_TYPES_HPP + +#include + +namespace libtorrent { namespace dht +{ + struct public_key + { + public_key() = default; + explicit public_key(char const* b) + { std::copy(b, b + len, bytes.begin()); } + bool operator==(public_key const& rhs) const + { return bytes == rhs.bytes; } + constexpr static int len = 32; + std::array bytes; + }; + + struct secret_key + { + secret_key() = default; + explicit secret_key(char const* b) + { std::copy(b, b + len, bytes.begin()); } + bool operator==(secret_key const& rhs) const + { return bytes == rhs.bytes; } + constexpr static int len = 64; + std::array bytes; + }; + + struct signature + { + signature() = default; + explicit signature(char const* b) + { std::copy(b, b + len, bytes.begin()); } + bool operator==(signature const& rhs) const + { return bytes == rhs.bytes; } + constexpr static int len = 64; + std::array bytes; + }; + + struct sequence_number + { + sequence_number() : value(0) {} + explicit sequence_number(std::uint64_t v) : value(v) {} + sequence_number(sequence_number const& sqn) = default; + bool operator<(sequence_number rhs) const + { return value < rhs.value; } + bool operator>(sequence_number rhs) const + { return value > rhs.value; } + sequence_number& operator=(sequence_number rhs) + { value = rhs.value; return *this; } + bool operator<=(sequence_number rhs) const + { return value <= rhs.value; } + bool operator==(sequence_number const& rhs) const + { return value == rhs.value; } + sequence_number& operator++() + { ++value; return *this; } + std::uint64_t value; + }; + +}} + +#endif // LIBTORRENT_TYPES_HPP + diff --git a/include/libtorrent/session_handle.hpp b/include/libtorrent/session_handle.hpp index fed9f3802..41fb4c39c 100644 --- a/include/libtorrent/session_handle.hpp +++ b/include/libtorrent/session_handle.hpp @@ -419,7 +419,7 @@ namespace libtorrent // calling the callback in between is convenient. void dht_put_item(std::array key , boost::function& - , std::uint64_t&, std::string const&)> cb + , std::uint64_t&, std::string const&)> cb , std::string salt = std::string()); void dht_get_peers(sha1_hash const& info_hash); diff --git a/include/libtorrent/stack_allocator.hpp b/include/libtorrent/stack_allocator.hpp index 926d8d46e..c956e7feb 100644 --- a/include/libtorrent/stack_allocator.hpp +++ b/include/libtorrent/stack_allocator.hpp @@ -84,6 +84,7 @@ namespace libtorrent { namespace aux return ret; } + // TODO: 3 use span<> here int copy_buffer(char const* buf, int const size) { int const ret = int(m_storage.size()); diff --git a/simulation/test_dht.cpp b/simulation/test_dht.cpp index 78866ee4c..b7235af5d 100644 --- a/simulation/test_dht.cpp +++ b/simulation/test_dht.cpp @@ -284,8 +284,8 @@ TORRENT_TEST(dht_dual_stack_mutable_item) dht_network dht(sim, 100); dht_network dht6(sim, 100, dht_network::bind_ipv6); - std::array sk; - std::array pk; + lt::dht::secret_key sk; + lt::dht::public_key pk; int put_count = 0; bool got_item = false; @@ -302,7 +302,7 @@ TORRENT_TEST(dht_dual_stack_mutable_item) { TEST_CHECK(!got_item); if (p->authoritative) - got_item = p->key == pk && p->item.string() == "mutable item"; + got_item = p->key == pk.bytes && p->item.string() == "mutable item"; } } // terminate? @@ -315,28 +315,28 @@ TORRENT_TEST(dht_dual_stack_mutable_item) if (ticks == 2) { std::array seed; - ed25519_create_keypair((unsigned char*)pk.data() - , (unsigned char*)sk.data(), seed.data()); + ed25519_create_keypair((unsigned char*)pk.bytes.data() + , (unsigned char*)sk.bytes.data(), seed.data()); - ses.dht_put_item(pk, [&](lt::entry& item, std::array& sig + ses.dht_put_item(pk.bytes, [&](lt::entry& item, std::array& sig , std::uint64_t& seq, std::string const& salt) { item = "mutable item"; seq = 1; std::vector v; + lt::dht::signature sign; lt::bencode(std::back_inserter(v), item); - lt::dht::sign_mutable_item( - std::make_pair(v.data(), int(v.size())) - , std::make_pair(salt.data(), int(salt.size())) - , seq, pk.data(), sk.data(), sig.data()); + lt::dht::sign_mutable_item(v, salt + , lt::dht::sequence_number(seq), pk, sk, sign); put_count++; + sig = sign.bytes; }); } if (ticks == 4) { // should be one for each stack, ipv4 and ipv6 TEST_EQUAL(put_count, 2); - ses.dht_get_item(pk); + ses.dht_get_item(pk.bytes); } if (ticks == 6) { diff --git a/simulation/test_dht_storage.cpp b/simulation/test_dht_storage.cpp index 4feafd29f..ee9d70279 100644 --- a/simulation/test_dht_storage.cpp +++ b/simulation/test_dht_storage.cpp @@ -107,7 +107,7 @@ void test_expiration(high_resolution_clock::duration const& expiry_time { default_config cfg; simulation sim(cfg); - sim::asio::io_service ios(sim, asio::ip::address_v4::from_string("10.0.0.1")); + sim::asio::io_service ios(sim, addr("10.0.0.1")); sim::asio::high_resolution_timer timer(ios); timer.expires_from_now(expiry_time); @@ -139,16 +139,15 @@ TORRENT_TEST(dht_storage_counters) s->announce_peer(n2, p3, "torrent_name1", false); s->announce_peer(n3, p4, "torrent_name2", false); - s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n4, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n1, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21")); - s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); - - char public_key[item_pk_len]; - char signature[item_sig_len]; - s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4 - , address::from_string("124.31.75.21")); + dht::public_key pk; + dht::signature sig; + s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk, {"salt", 4} + , addr("124.31.75.21")); dht_storage_counters c; // note that we are using the aux global timer diff --git a/src/alert.cpp b/src/alert.cpp index 4365c8a11..bc964d4f0 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -1886,6 +1886,7 @@ namespace libtorrent { return ret; } + // TODO: 3 use span<> here dht_pkt_alert::dht_pkt_alert(aux::stack_allocator& alloc , char const* buf, int size, dht_pkt_alert::direction_t d, udp::endpoint ep) : dir(d) @@ -1987,8 +1988,9 @@ namespace libtorrent { aux::stack_allocator& alloc, void* userdata_ , udp::endpoint const& addr_, bdecode_node const& response) : userdata(userdata_), addr(addr_), m_alloc(alloc) - , m_response_idx(alloc.copy_buffer(response.data_section().first, response.data_section().second)) - , m_response_size(response.data_section().second) + , m_response_idx(alloc.copy_buffer(response.data_section().data() + , int(response.data_section().size()))) + , m_response_size(int(response.data_section().size())) {} dht_direct_response_alert::dht_direct_response_alert( diff --git a/src/bdecode.cpp b/src/bdecode.cpp index f8a65bb42..79718a3e2 100644 --- a/src/bdecode.cpp +++ b/src/bdecode.cpp @@ -303,14 +303,14 @@ namespace libtorrent bdecode_node::operator bool() const { return m_token_idx != -1; } - std::pair bdecode_node::data_section() const + span bdecode_node::data_section() const { - if (m_token_idx == -1) return std::make_pair(m_buffer, 0); + if (m_token_idx == -1) return span(); TORRENT_ASSERT(m_token_idx != -1); bdecode_token const& t = m_root_tokens[m_token_idx]; bdecode_token const& next = m_root_tokens[m_token_idx + t.next_item]; - return std::make_pair(m_buffer + t.offset, next.offset - t.offset); + return { m_buffer + t.offset, size_t(next.offset - t.offset) }; } bdecode_node bdecode_node::list_at(int i) const diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 97dd327fa..d3249c706 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -95,8 +95,8 @@ namespace libtorrent , sha1_hash const& stream_key, bool const outgoing) { hasher h; - static const char keyA[] = "keyA"; - static const char keyB[] = "keyB"; + static const char keyA[] = {'k', 'e', 'y', 'A'}; + static const char keyB[] = {'k', 'e', 'y', 'B'}; // encryption rc4 longkeys // outgoing connection : hash ('keyA',S,SKEY) @@ -105,10 +105,10 @@ namespace libtorrent std::array secret_buf; mp::export_bits(secret, reinterpret_cast(secret_buf.data()), 8); - if (outgoing) h.update(keyA, 4); else h.update(keyB, 4); + if (outgoing) h.update(keyA); else h.update(keyB); h.update(secret_buf); h.update(stream_key); - const sha1_hash local_key = h.final(); + sha1_hash const local_key = h.final(); h.reset(); @@ -116,10 +116,10 @@ namespace libtorrent // outgoing connection : hash ('keyB',S,SKEY) // incoming connection : hash ('keyA',S,SKEY) - if (outgoing) h.update(keyB, 4); else h.update(keyA, 4); + if (outgoing) h.update(keyB); else h.update(keyA); h.update(secret_buf); h.update(stream_key); - const sha1_hash remote_key = h.final(); + sha1_hash const remote_key = h.final(); boost::shared_ptr ret = boost::make_shared(); @@ -557,27 +557,30 @@ namespace libtorrent char msg[20 + 20 + 8 + 4 + 2 + 512 + 2]; char* ptr = msg; + static char const req1[4] = {'r', 'e', 'q', '1'}; // sync hash (hash('req1',S)) h.reset(); - h.update("req1",4); + h.update(req1); h.update(secret); sha1_hash const sync_hash = h.final(); - memcpy(ptr, sync_hash.data(), 20); + std::memcpy(ptr, sync_hash.data(), 20); ptr += 20; + static char const req2[4] = {'r', 'e', 'q', '2'}; // stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ] h.reset(); - h.update("req2",4); + h.update(req2); h.update(info_hash); sha1_hash const streamkey_hash = h.final(); + static char const req3[4] = {'r', 'e', 'q', '3'}; h.reset(); - h.update("req3",4); + h.update(req3); h.update(secret); sha1_hash const obfsc_hash = h.final() ^ streamkey_hash; - memcpy(ptr, obfsc_hash.data(), 20); + std::memcpy(ptr, obfsc_hash.data(), 20); ptr += 20; // Discard DH key exchange data, setup RC4 keys @@ -726,7 +729,7 @@ namespace libtorrent // if we're encrypting this buffer, we need to make a copy // since we'll mutate it char* buf = static_cast(malloc(size)); - memcpy(buf, buffer, size); + std::memcpy(buf, buffer, size); append_send_buffer(buf, size, ®ular_c_free, nullptr); destructor(const_cast(buffer), userdata, ref); } @@ -757,7 +760,7 @@ namespace libtorrent // length of version string detail::write_uint8(string_len, ptr); // protocol identifier - memcpy(ptr, version_string, string_len); + std::memcpy(ptr, version_string, string_len); ptr += string_len; // 8 zeroes memset(ptr, 0, 8); @@ -798,7 +801,7 @@ namespace libtorrent // info hash sha1_hash const& ih = t->torrent_file().info_hash(); - memcpy(ptr, &ih[0], 20); + std::memcpy(ptr, ih.data(), ih.size()); ptr += 20; // peer id @@ -810,7 +813,7 @@ namespace libtorrent m_our_peer_id[i] = random() & 0xff; } - memcpy(ptr, &m_our_peer_id[0], 20); + std::memcpy(ptr, m_our_peer_id.data(), 20); ptr += 20; #ifndef TORRENT_DISABLE_LOGGING @@ -2632,15 +2635,14 @@ namespace libtorrent if (!m_sync_hash.get()) { TORRENT_ASSERT(m_sync_bytes_read == 0); - hasher h; + static char const req1[4] = {'r', 'e', 'q', '1'}; // compute synchash (hash('req1',S)) std::array buffer; mp::export_bits(m_dh_key_exchange->get_secret() , reinterpret_cast(buffer.data()), 8); - h.update("req1", 4); + hasher h(req1); h.update(buffer); - m_sync_hash.reset(new sha1_hash(h.final())); } diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index 22eb63eeb..b1ccdea66 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -570,7 +570,7 @@ namespace libtorrent std::string split = split_path(m_files.symlink(0)); for (char const* e = split.c_str(); e != nullptr; e = next_path_element(e)) - sympath_e.list().push_back(entry(e)); + sympath_e.list().push_back(e); } if (!m_filehashes.empty()) { diff --git a/src/kademlia/dht_storage.cpp b/src/kademlia/dht_storage.cpp index 8b9fabe40..bcaa589af 100644 --- a/src/kademlia/dht_storage.cpp +++ b/src/kademlia/dht_storage.cpp @@ -85,27 +85,13 @@ namespace std::set peers; }; -#ifndef TORRENT_NO_DEPRECATE - struct count_peers - { - int* count; - explicit count_peers(int* c): count(c) {} - void operator()(std::pair const& t) - { - *count += int(t.second.peers.size()); - } - }; -#endif - // TODO: 2 make this configurable in dht_settings enum { announce_interval = 30 }; struct dht_immutable_item { - dht_immutable_item() : value(nullptr), num_announcers(0), size(0) {} - // malloced space for the actual value - char* value; + // the actual value + std::unique_ptr value; // this counts the number of IPs we have seen // announcing this item, this is used to determine // popularity if we reach the limit of items to store @@ -113,20 +99,17 @@ namespace // the last time we heard about this time_point last_seen; // number of IPs in the bloom filter - int num_announcers; + int num_announcers = 0; // size of malloced space pointed to by value - int size; + int size = 0; }; - struct ed25519_public_key { char bytes[item_pk_len]; }; - struct dht_mutable_item : dht_immutable_item { - char sig[item_sig_len]; - std::int64_t seq; - ed25519_public_key key; - char* salt; - int salt_size; + signature sig; + sequence_number seq; + public_key key; + std::string salt; }; void touch_item(dht_immutable_item* f, address const& address) @@ -150,11 +133,12 @@ namespace explicit immutable_item_comparator(std::vector const& node_ids) : m_node_ids(node_ids) {} immutable_item_comparator(immutable_item_comparator const&) = default; - bool operator() (std::pair const& lhs - , std::pair const& rhs) const + template + bool operator()(std::pair const& lhs + , std::pair const& rhs) const { - int l_distance = min_distance_exp(lhs.first, m_node_ids); - int r_distance = min_distance_exp(rhs.first, m_node_ids); + int const l_distance = min_distance_exp(lhs.first, m_node_ids); + int const r_distance = min_distance_exp(rhs.first, m_node_ids); // this is a score taking the popularity (number of announcers) and the // fit, in terms of distance from ideal storing node, into account. @@ -180,16 +164,15 @@ namespace typename std::map::const_iterator pick_least_important_item( std::vector const& node_ids, std::map const& table) { - return std::min_element(table.begin() - , table.end() + return std::min_element(table.begin(), table.end() , immutable_item_comparator(node_ids)); } class dht_default_storage final : public dht_storage_interface, boost::noncopyable { - typedef std::map table_t; - typedef std::map dht_immutable_table_t; - typedef std::map dht_mutable_table_t; + using table_t = std::map; + using dht_immutable_table_t = std::map; + using dht_mutable_table_t = std::map; public: @@ -205,8 +188,9 @@ namespace size_t num_torrents() const override { return m_map.size(); } size_t num_peers() const override { - int ret = 0; - std::for_each(m_map.begin(), m_map.end(), count_peers(&ret)); + size_t ret = 0; + for (auto const& t : m_map) + ret += t.second.peers.size(); return ret; } #endif @@ -216,7 +200,7 @@ namespace } bool get_peers(sha1_hash const& info_hash - , bool noseed, bool scrape + , bool const noseed, bool const scrape , entry& peers) const override { table_t::const_iterator i = m_map.lower_bound(info_hash); @@ -275,7 +259,7 @@ namespace void announce_peer(sha1_hash const& info_hash , tcp::endpoint const& endp - , std::string const& name, bool seed) override + , std::string const& name, bool const seed) override { table_t::iterator ti = m_map.find(info_hash); torrent_entry* v; @@ -348,12 +332,13 @@ namespace dht_immutable_table_t::const_iterator i = m_immutable_table.find(target); if (i == m_immutable_table.end()) return false; - item["v"] = bdecode(i->second.value, i->second.value + i->second.size); + item["v"] = bdecode(i->second.value.get() + , i->second.value.get() + i->second.size); return true; } void put_immutable_item(sha1_hash const& target - , char const* buf, int size + , span buf , address const& addr) override { TORRENT_ASSERT(!m_node_ids.empty()); @@ -367,17 +352,16 @@ namespace , m_immutable_table); TORRENT_ASSERT(j != m_immutable_table.end()); - free(j->second.value); m_immutable_table.erase(j); m_counters.immutable_data -= 1; } dht_immutable_item to_add; - to_add.value = static_cast(malloc(size)); - to_add.size = size; - memcpy(to_add.value, buf, size); + to_add.value.reset(new char[buf.size()]); + to_add.size = int(buf.size()); + memcpy(to_add.value.get(), buf.data(), buf.size()); std::tie(i, std::ignore) = m_immutable_table.insert( - std::make_pair(target, to_add)); + std::make_pair(target, std::move(to_add))); m_counters.immutable_data += 1; } @@ -387,7 +371,7 @@ namespace } bool get_mutable_item_seq(sha1_hash const& target - , std::int64_t& seq) const override + , sequence_number& seq) const override { dht_mutable_table_t::const_iterator i = m_mutable_table.find(target); if (i == m_mutable_table.end()) return false; @@ -397,29 +381,29 @@ namespace } bool get_mutable_item(sha1_hash const& target - , std::int64_t seq, bool force_fill + , sequence_number seq, bool force_fill , entry& item) const override { dht_mutable_table_t::const_iterator i = m_mutable_table.find(target); if (i == m_mutable_table.end()) return false; dht_mutable_item const& f = i->second; - item["seq"] = f.seq; - if (force_fill || (0 <= seq && seq < f.seq)) + item["seq"] = f.seq.value; + if (force_fill || (sequence_number(0) <= seq && seq < f.seq)) { - item["v"] = bdecode(f.value, f.value + f.size); - item["sig"] = std::string(f.sig, f.sig + sizeof(f.sig)); - item["k"] = std::string(f.key.bytes, f.key.bytes + sizeof(f.key.bytes)); + item["v"] = bdecode(f.value.get(), f.value.get() + f.size); + item["sig"] = f.sig.bytes; + item["k"] = f.key.bytes; } return true; } void put_mutable_item(sha1_hash const& target - , char const* buf, int size - , char const* sig - , std::int64_t seq - , char const* pk - , char const* salt, int salt_size + , span buf + , signature const& sig + , sequence_number seq + , public_key const& pk + , span salt , address const& addr) override { TORRENT_ASSERT(!m_node_ids.empty()); @@ -434,47 +418,37 @@ namespace , m_mutable_table); TORRENT_ASSERT(j != m_mutable_table.end()); - free(j->second.value); - free(j->second.salt); m_mutable_table.erase(j); m_counters.mutable_data -= 1; } dht_mutable_item to_add; - to_add.value = static_cast(malloc(size)); - to_add.size = size; + to_add.value.reset(new char[buf.size()]); + to_add.size = int(buf.size()); to_add.seq = seq; - to_add.salt = nullptr; - to_add.salt_size = 0; - if (salt_size > 0) - { - to_add.salt = static_cast(malloc(salt_size)); - to_add.salt_size = salt_size; - memcpy(to_add.salt, salt, salt_size); - } - memcpy(to_add.sig, sig, sizeof(to_add.sig)); - memcpy(to_add.value, buf, size); - memcpy(&to_add.key, pk, sizeof(to_add.key)); + to_add.salt.assign(salt.data(), salt.size()); + to_add.sig = sig; + to_add.key = pk; + memcpy(to_add.value.get(), buf.data(), buf.size()); std::tie(i, std::ignore) = m_mutable_table.insert( - std::make_pair(target, to_add)); + std::make_pair(target, std::move(to_add))); m_counters.mutable_data += 1; } else { // this is the case where we already - dht_mutable_item* item = &i->second; + dht_mutable_item& item = i->second; - if (item->seq < seq) + if (item.seq < seq) { - if (item->size != size) + if (item.size != buf.size()) { - free(item->value); - item->value = static_cast(malloc(size)); - item->size = size; + item.value.reset(new char[buf.size()]); + item.size = int(buf.size()); } - item->seq = seq; - memcpy(item->sig, sig, sizeof(item->sig)); - memcpy(item->value, buf, size); + item.seq = seq; + item.sig = sig; + memcpy(item.value.get(), buf.data(), buf.size()); } } @@ -516,7 +490,6 @@ namespace ++i; continue; } - free(i->second.value); m_immutable_table.erase(i++); m_counters.immutable_data -= 1; } @@ -529,8 +502,6 @@ namespace ++i; continue; } - free(i->second.value); - free(i->second.salt); m_mutable_table.erase(i++); m_counters.mutable_data -= 1; } @@ -556,7 +527,7 @@ namespace , end(peers.end()); i != end;) { // the peer has timed out - if (i->added + minutes(int(announce_interval * 1.5f)) < aux::time_now()) + if (i->added + minutes(int(announce_interval * 3 / 2)) < aux::time_now()) { peers.erase(i++); m_counters.peers -= 1; diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index 7ddf2f799..3669802c7 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -444,7 +444,7 @@ namespace libtorrent { namespace dht // key is a 32-byte binary string, the public key to look up. // the salt is optional - void dht_tracker::get_item(char const* key + void dht_tracker::get_item(public_key const& key , boost::function cb , std::string salt) { @@ -461,8 +461,7 @@ namespace libtorrent { namespace dht { std::string flat_data; bencode(std::back_inserter(flat_data), data); - sha1_hash target = item_target_id( - std::pair(flat_data.c_str(), flat_data.size())); + sha1_hash const target = item_target_id(flat_data); boost::shared_ptr ctx = boost::make_shared((TORRENT_USE_IPV6) ? 2 : 1); @@ -474,7 +473,7 @@ namespace libtorrent { namespace dht #endif } - void dht_tracker::put_item(char const* key + void dht_tracker::put_item(public_key const& key , boost::function cb , boost::function data_cb, std::string salt) { diff --git a/src/kademlia/get_item.cpp b/src/kademlia/get_item.cpp index 3828c56d1..bf5488545 100644 --- a/src/kademlia/get_item.cpp +++ b/src/kademlia/get_item.cpp @@ -45,9 +45,9 @@ namespace libtorrent { namespace dht { void get_item::got_data(bdecode_node const& v, - char const* pk, - std::uint64_t seq, - char const* sig) + public_key const& pk, + sequence_number const seq, + signature const& sig) { // we received data! // if no data_callback, we needn't care about the data we get. @@ -74,13 +74,11 @@ void get_item::got_data(bdecode_node const& v, return; } - // immutalbe data should has been handled before this line, only mutable - // data can reach here, which means pk and sig must be valid. - if (!pk || !sig) return; + // immutable data should have been handled before this line, only mutable + // data can reach here, which means pk, sig and seq must be valid. - std::string temp_copy(m_data.salt()); - std::pair salt(temp_copy.c_str(), int(temp_copy.size())); - sha1_hash incoming_target = item_target_id(salt, pk); + std::string const salt_copy(m_data.salt()); + sha1_hash const incoming_target = item_target_id(salt_copy, pk); if (incoming_target != m_target) return; // this is mutable data. If it passes the signature @@ -88,7 +86,7 @@ void get_item::got_data(bdecode_node const& v, // the highest sequence number. if (m_data.empty() || m_data.seq() < seq) { - if (!m_data.assign(v, salt, seq, pk, sig)) + if (!m_data.assign(v, salt_copy, seq, pk, sig)) return; // for get_item, we should call callback when we get data, @@ -114,13 +112,11 @@ get_item::get_item( get_item::get_item( node& dht_node - , char const* pk - , std::string const& salt + , public_key const& pk + , span salt , data_callback const& dcallback , nodes_callback const& ncallback) - : find_data(dht_node, item_target_id( - std::make_pair(salt.c_str(), int(salt.size())), pk) - , ncallback) + : find_data(dht_node, item_target_id(salt, pk), ncallback) , m_data_callback(dcallback) , m_data(pk, salt) , m_immutable(false) @@ -172,10 +168,7 @@ void get_item::done() #if TORRENT_USE_ASSERTS if (m_data.is_mutable()) { - TORRENT_ASSERT(m_target - == item_target_id(std::pair(m_data.salt().c_str() - , m_data.salt().size()) - , m_data.pk().data())); + TORRENT_ASSERT(m_target == item_target_id(m_data.salt(), m_data.pk())); } #endif } @@ -185,9 +178,9 @@ void get_item::done() void get_item_observer::reply(msg const& m) { - char const* pk = nullptr; - char const* sig = nullptr; - std::uint64_t seq = 0; + public_key pk; + signature sig; + sequence_number seq{0}; bdecode_node r = m.message.dict_find_dict("r"); if (!r) @@ -201,17 +194,19 @@ void get_item_observer::reply(msg const& m) } bdecode_node k = r.dict_find_string("k"); - if (k && k.string_length() == item_pk_len) - pk = k.string_ptr(); + if (k && k.string_length() == public_key::len) + std::memcpy(pk.bytes.data(), k.string_ptr(), public_key::len); bdecode_node s = r.dict_find_string("sig"); - if (s && s.string_length() == item_sig_len) - sig = s.string_ptr(); + if (s && s.string_length() == signature::len) + std::memcpy(sig.bytes.data(), s.string_ptr(), signature::len); bdecode_node q = r.dict_find_int("seq"); if (q) - seq = q.int_value(); - else if (pk && sig) + { + seq = sequence_number(q.int_value()); + } + else if (k && s) { timeout(); return; diff --git a/src/kademlia/item.cpp b/src/kademlia/item.cpp index 2ee5549fb..aeddc4cf7 100644 --- a/src/kademlia/item.cpp +++ b/src/kademlia/item.cpp @@ -33,10 +33,12 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include // for snprintf #include // for PRId64 et.al. +#include // for memcpy #if TORRENT_USE_ASSERTS #include "libtorrent/bdecode.hpp" @@ -47,67 +49,67 @@ namespace libtorrent { namespace dht namespace { - enum { canonical_length = 1200 }; - int canonical_string(std::pair v, std::uint64_t seq - , std::pair salt, char out[canonical_length]) + int canonical_string(span v + , sequence_number const seq + , span salt + , span out) { // v must be valid bencoding! #if TORRENT_USE_ASSERTS bdecode_node e; error_code ec; - TORRENT_ASSERT(bdecode(v.first, v.first + v.second, e, ec) == 0); + TORRENT_ASSERT(bdecode(v.data(), v.data() + v.size(), e, ec) == 0); #endif - char* ptr = out; + char* ptr = out.data(); - int left = canonical_length - (ptr - out); - if (salt.second > 0) + size_t left = out.size() - (ptr - out.data()); + if (salt.size() > 0) { - ptr += std::snprintf(ptr, left, "4:salt%d:", salt.second); - left = canonical_length - (ptr - out); - memcpy(ptr, salt.first, (std::min)(salt.second, left)); - ptr += (std::min)(salt.second, left); - left = canonical_length - (ptr - out); + ptr += std::snprintf(ptr, left, "4:salt%d:", int(salt.size())); + left = out.size() - (ptr - out.data()); + std::memcpy(ptr, salt.data(), (std::min)(salt.size(), left)); + ptr += (std::min)(salt.size(), left); + left = out.size() - (ptr - out.data()); } - ptr += std::snprintf(ptr, canonical_length - (ptr - out) - , "3:seqi%" PRId64 "e1:v", seq); - left = canonical_length - (ptr - out); - memcpy(ptr, v.first, (std::min)(v.second, left)); - ptr += (std::min)(v.second, left); - TORRENT_ASSERT((ptr - out) <= canonical_length); - return ptr - out; + ptr += std::snprintf(ptr, out.size() - (ptr - out.data()) + , "3:seqi%" PRId64 "e1:v", seq.value); + left = out.size() - (ptr - out.data()); + std::memcpy(ptr, v.data(), (std::min)(v.size(), left)); + ptr += (std::min)(v.size(), left); + TORRENT_ASSERT((ptr - out.data()) <= out.size()); + return ptr - out.data(); } } // calculate the target hash for an immutable item. -sha1_hash item_target_id(std::pair v) +sha1_hash item_target_id(span v) { - return hasher(v.first, v.second).final(); + return hasher(v).final(); } // calculate the target hash for a mutable item. -sha1_hash item_target_id(std::pair salt - , char const* pk) +sha1_hash item_target_id(span salt + , public_key const& pk) { - hasher h; - h.update(pk, item_pk_len); - if (salt.second > 0) h.update(salt.first, salt.second); + hasher h(pk.bytes); + if (salt.size() > 0) h.update(salt); return h.final(); } bool verify_mutable_item( - std::pair v - , std::pair salt - , std::uint64_t seq - , char const* pk - , char const* sig) + span v + , span salt + , sequence_number const seq + , public_key const& pk + , signature const& sig) { - char str[canonical_length]; + char str[1200]; int len = canonical_string(v, seq, salt, str); - return ed25519_verify(reinterpret_cast(sig) + return ed25519_verify(reinterpret_cast(sig.bytes.data()) , reinterpret_cast(str) , len - , reinterpret_cast(pk)) == 1; + , reinterpret_cast(pk.bytes.data())) == 1; } // given the bencoded buffer ``v``, the salt (which is optional and may have @@ -117,104 +119,107 @@ bool verify_mutable_item( // at least 64 bytes of available space. This space is where the signature is // written. void sign_mutable_item( - std::pair v - , std::pair salt - , std::uint64_t seq - , char const* pk - , char const* sk - , char* sig) + span v + , span salt + , sequence_number const seq + , public_key const& pk + , secret_key const& sk + , signature& sig) { - char str[canonical_length]; - int len = canonical_string(v, seq, salt, str); + char str[1200]; + int const len = canonical_string(v, seq, salt, str); - ed25519_sign(reinterpret_cast(sig) + ed25519_sign(reinterpret_cast(sig.bytes.data()) , reinterpret_cast(str) , len - , reinterpret_cast(pk) - , reinterpret_cast(sk) + , reinterpret_cast(pk.bytes.data()) + , reinterpret_cast(sk.bytes.data()) ); } -item::item(char const* pk, std::string const& salt) - : m_salt(salt) +item::item(public_key const& pk, span salt) + : m_salt(salt.data(), salt.size()) + , m_pk(pk) , m_seq(0) , m_mutable(true) +{} + +item::item(entry v) + : m_value(std::move(v)) + , m_seq(0) + , m_mutable(false) +{} + +item::item(bdecode_node const& v) + : m_value(std::move(v)) + , m_seq(0) + , m_mutable(false) +{} + +item::item(entry v, span salt + , sequence_number const seq, public_key const& pk, secret_key const& sk) { - memcpy(m_pk.data(), pk, item_pk_len); + assign(std::move(v), salt, seq, pk, sk); } -item::item(entry const& v - , std::pair salt - , std::uint64_t seq, char const* pk, char const* sk) +void item::assign(entry v) { - assign(v, salt, seq, pk, sk); + m_mutable = false; + m_value = std::move(v); } -void item::assign(entry const& v, std::pair salt - , std::uint64_t seq, char const* pk, char const* sk) +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); + TORRENT_ASSERT(bsize <= 1000); + sign_mutable_item(span(buffer, bsize) + , salt, seq, pk, sk, m_sig); + m_salt.assign(salt.data(), salt.size()); + m_pk = pk; + m_seq = seq; + m_mutable = true; + m_value = std::move(v); +} + +void item::assign(bdecode_node const& v) +{ + m_mutable = false; m_value = v; - if (pk && sk) - { - char buffer[1000]; - int bsize = bencode(buffer, v); - TORRENT_ASSERT(bsize <= 1000); - sign_mutable_item(std::make_pair(buffer, bsize) - , salt, seq, pk, sk, m_sig.data()); - m_salt.assign(salt.first, salt.second); - memcpy(m_pk.data(), pk, item_pk_len); - m_seq = seq; - m_mutable = true; - } - else - m_mutable = false; } -bool item::assign(bdecode_node const& v - , std::pair salt - , std::uint64_t seq, char const* pk, char const* sig) +bool item::assign(bdecode_node const& v, span salt + , sequence_number const seq, public_key const& pk, signature const& sig) { - TORRENT_ASSERT(v.data_section().second <= 1000); - if (pk && sig) - { - if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig)) - return false; - memcpy(m_pk.data(), pk, item_pk_len); - memcpy(m_sig.data(), sig, item_sig_len); - if (salt.second > 0) - m_salt.assign(salt.first, salt.second); - else - m_salt.clear(); - m_seq = seq; - m_mutable = true; - } + TORRENT_ASSERT(v.data_section().size() <= 1000); + if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig)) + return false; + m_pk = pk; + m_sig = sig; + if (salt.size() > 0) + m_salt.assign(salt.data(), salt.size()); else - m_mutable = false; + m_salt.clear(); + m_seq = seq; + m_mutable = true; m_value = v; return true; } -void item::assign(entry const& v, std::string salt, std::uint64_t seq - , char const* pk, char const* sig) +void item::assign(entry v, span salt + , sequence_number const seq + , public_key const& pk, signature const& sig) { -#if TORRENT_USE_ASSERTS - TORRENT_ASSERT(pk && sig); - char buffer[1000]; - int bsize = bencode(buffer, v); - TORRENT_ASSERT(bsize <= 1000); - TORRENT_ASSERT(verify_mutable_item( - std::make_pair(buffer, bsize) - , std::make_pair(salt.data(), int(salt.size())) - , seq, pk, sig)); -#endif - memcpy(m_pk.data(), pk, item_pk_len); - memcpy(m_sig.data(), sig, item_sig_len); - m_salt = salt; + m_pk = pk; + m_sig = sig; + m_salt.assign(salt.data(), salt.size()); m_seq = seq; m_mutable = true; - m_value = v; + m_value = std::move(v); } } } // namespace libtorrent::dht + diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index 39785b7f8..12548118d 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -145,7 +145,7 @@ void node::update_node_id() m_table.update_node_id(m_id); } -bool node::verify_token(std::string const& token, char const* info_hash +bool node::verify_token(std::string const& token, sha1_hash const& info_hash , udp::endpoint const& addr) const { if (token.length() != 4) @@ -166,7 +166,7 @@ bool node::verify_token(std::string const& token, char const* info_hash if (ec) return false; h1.update(address); h1.update(reinterpret_cast(&m_secret[0]), sizeof(m_secret[0])); - h1.update(info_hash, 20); + h1.update(info_hash); sha1_hash h = h1.final(); if (std::equal(token.begin(), token.end(), reinterpret_cast(&h[0]))) @@ -175,7 +175,7 @@ bool node::verify_token(std::string const& token, char const* info_hash hasher h2; h2.update(address); h2.update(reinterpret_cast(&m_secret[1]), sizeof(m_secret[1])); - h2.update(info_hash, 20); + h2.update(info_hash); h = h2.final(); if (std::equal(token.begin(), token.end(), reinterpret_cast(&h[0]))) return true; @@ -183,7 +183,7 @@ bool node::verify_token(std::string const& token, char const* info_hash } std::string node::generate_token(udp::endpoint const& addr - , char const* info_hash) + , sha1_hash const& info_hash) { std::string token; token.resize(4); @@ -193,7 +193,7 @@ std::string node::generate_token(udp::endpoint const& addr TORRENT_ASSERT(!ec); h.update(address); h.update(reinterpret_cast(&m_secret[0]), sizeof(m_secret[0])); - h.update(info_hash, 20); + h.update(info_hash); sha1_hash const hash = h.final(); std::copy(hash.begin(), hash.begin() + 4, reinterpret_cast(&token[0])); @@ -360,7 +360,7 @@ namespace if (node.observer()) { char hex_ih[41]; - aux::to_hex(reinterpret_cast(&ih[0]), 20, hex_ih); + aux::to_hex(ih.data(), 20, hex_ih); node.observer()->log(dht_logger::node, "sending announce_peer [ ih: %s " " p: %d nodes: %d ]", hex_ih, listen_port, int(v.size())); } @@ -391,7 +391,7 @@ namespace e["y"] = "q"; e["q"] = "announce_peer"; entry& a = e["a"]; - a["info_hash"] = ih.to_string(); + a["info_hash"] = ih; a["port"] = listen_port; a["token"] = i->second; a["seed"] = (flags & node::flag_seed) ? 1 : 0; @@ -450,7 +450,7 @@ void node::announce(sha1_hash const& info_hash, int listen_port, int flags if (m_observer) { char hex_ih[41]; - aux::to_hex(reinterpret_cast(&info_hash[0]), 20, hex_ih); + aux::to_hex(info_hash.data(), 20, hex_ih); m_observer->log(dht_logger::node, "announcing [ ih: %s p: %d ]" , hex_ih, listen_port); } @@ -484,7 +484,7 @@ void node::get_item(sha1_hash const& target if (m_observer) { char hex_target[41]; - aux::to_hex(reinterpret_cast(&target[0]), 20, hex_target); + aux::to_hex(target.data(), 20, hex_target); m_observer->log(dht_logger::node, "starting get for [ hash: %s ]" , hex_target); } @@ -495,14 +495,14 @@ void node::get_item(sha1_hash const& target ta->start(); } -void node::get_item(char const* pk, std::string const& salt +void node::get_item(public_key const& pk, std::string const& salt , boost::function f) { #ifndef TORRENT_DISABLE_LOGGING if (m_observer) { char hex_key[65]; - aux::to_hex(pk, 32, hex_key); + aux::to_hex(pk.bytes.data(), 32, hex_key); m_observer->log(dht_logger::node, "starting get for [ key: %s ]", hex_key); } #endif @@ -559,7 +559,7 @@ void node::put_item(sha1_hash const& target, entry const& data, boost::function< ta->start(); } -void node::put_item(char const* pk, std::string const& salt +void node::put_item(public_key const& pk, std::string const& salt , boost::function f , boost::function data_cb) { @@ -567,7 +567,7 @@ void node::put_item(char const* pk, std::string const& salt if (m_observer) { char hex_key[65]; - aux::to_hex(pk, 32, hex_key); + aux::to_hex(pk.bytes.data(), 32, hex_key); m_observer->log(dht_logger::node, "starting get for [ key: %s ]", hex_key); } #endif @@ -866,7 +866,7 @@ void node::incoming_request(msg const& m, entry& e) return; } - reply["token"] = generate_token(m.addr, msg_keys[0].string_ptr()); + reply["token"] = generate_token(m.addr, sha1_hash(msg_keys[0].string_ptr())); m_counters.inc_stats_counter(counters::dht_get_peers_in); @@ -944,7 +944,8 @@ void node::incoming_request(msg const& m, entry& e) if (m_observer) m_observer->announce(info_hash, m.addr.address(), port); - if (!verify_token(msg_keys[2].string_value(), msg_keys[0].string_ptr(), m.addr)) + if (!verify_token(msg_keys[2].string_value() + , sha1_hash(msg_keys[0].string_ptr()), m.addr)) { m_counters.inc_stats_counter(counters::dht_invalid_announce); incoming_error(e, "invalid token"); @@ -973,8 +974,8 @@ void node::incoming_request(msg const& m, entry& e) {"v", bdecode_node::none_t, 0, 0}, {"seq", bdecode_node::int_t, 0, key_desc_t::optional}, // public key - {"k", bdecode_node::string_t, item_pk_len, key_desc_t::optional}, - {"sig", bdecode_node::string_t, item_sig_len, key_desc_t::optional}, + {"k", bdecode_node::string_t, public_key::len, key_desc_t::optional}, + {"sig", bdecode_node::string_t, signature::len, key_desc_t::optional}, {"cas", bdecode_node::int_t, 0, key_desc_t::optional}, {"salt", bdecode_node::string_t, 0, key_desc_t::optional}, }; @@ -994,38 +995,35 @@ void node::incoming_request(msg const& m, entry& e) bool mutable_put = (msg_keys[2] && msg_keys[3] && msg_keys[4]); // public key (only set if it's a mutable put) - char const* pk = nullptr; - if (msg_keys[3]) pk = msg_keys[3].string_ptr(); + char const* pub_key = nullptr; + if (msg_keys[3]) pub_key = msg_keys[3].string_ptr(); // signature (only set if it's a mutable put) - char const* sig = nullptr; - if (msg_keys[4]) sig = msg_keys[4].string_ptr(); + char const* sign = nullptr; + if (msg_keys[4]) sign = msg_keys[4].string_ptr(); // pointer and length to the whole entry - std::pair buf = msg_keys[1].data_section(); - if (buf.second > 1000 || buf.second <= 0) + span buf = msg_keys[1].data_section(); + if (buf.size() > 1000 || buf.size() <= 0) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "message too big", 205); return; } - std::pair salt(static_cast(nullptr), 0); + span salt; if (msg_keys[6]) - salt = std::pair( - msg_keys[6].string_ptr(), msg_keys[6].string_length()); - if (salt.second > 64) + salt = { msg_keys[6].string_ptr(), size_t(msg_keys[6].string_length()) }; + if (salt.size() > 64) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "salt too big", 207); return; } - sha1_hash target; - if (pk) - target = item_target_id(salt, pk); - else - target = item_target_id(buf); + sha1_hash const target = pub_key + ? item_target_id(salt, public_key(pub_key)) + : item_target_id(buf); // std::fprintf(stderr, "%s PUT target: %s salt: %s key: %s\n" // , mutable_put ? "mutable":"immutable" @@ -1035,8 +1033,7 @@ void node::incoming_request(msg const& m, entry& e) // verify the write-token. tokens are only valid to write to // specific target hashes. it must match the one we got a "get" for - if (!verify_token(msg_keys[0].string_value() - , reinterpret_cast(&target[0]), m.addr)) + if (!verify_token(msg_keys[0].string_value(), target, m.addr)) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "invalid token"); @@ -1045,14 +1042,16 @@ void node::incoming_request(msg const& m, entry& e) if (!mutable_put) { - m_storage.put_immutable_item(target, buf.first, buf.second, m.addr.address()); + m_storage.put_immutable_item(target, buf, m.addr.address()); } else { // mutable put, we must verify the signature - std::int64_t const seq = msg_keys[2].int_value(); + sequence_number const seq(msg_keys[2].int_value()); + public_key const pk(pub_key); + signature const sig(sign); - if (seq < 0) + if (seq < sequence_number(0)) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "invalid (negative) sequence number"); @@ -1060,23 +1059,19 @@ void node::incoming_request(msg const& m, entry& e) } // msg_keys[4] is the signature, msg_keys[3] is the public key - if (!verify_mutable_item(buf, salt - , seq, pk, sig)) + if (!verify_mutable_item(buf, salt, seq, pk, sig)) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "invalid signature", 206); return; } - TORRENT_ASSERT(item_sig_len == msg_keys[4].string_length()); + TORRENT_ASSERT(signature::len == msg_keys[4].string_length()); - std::int64_t item_seq; + sequence_number item_seq; if (!m_storage.get_mutable_item_seq(target, item_seq)) { - m_storage.put_mutable_item(target - , buf.first, buf.second - , sig, seq, pk - , salt.first, salt.second + m_storage.put_mutable_item(target, buf, sig, seq, pk, salt , m.addr.address()); } else @@ -1086,7 +1081,7 @@ void node::incoming_request(msg const& m, entry& e) // number matches the expected value before replacing it // this is critical for avoiding race conditions when multiple // writers are accessing the same slot - if (msg_keys[5] && item_seq != msg_keys[5].int_value()) + if (msg_keys[5] && item_seq.value != msg_keys[5].int_value()) { m_counters.inc_stats_counter(counters::dht_invalid_put); incoming_error(e, "CAS mismatch", 301); @@ -1100,10 +1095,7 @@ void node::incoming_request(msg const& m, entry& e) return; } - m_storage.put_mutable_item(target - , buf.first, buf.second - , sig, seq, pk - , salt.first, salt.second + m_storage.put_mutable_item(target, buf, sig, seq, pk, salt , m.addr.address()); } } @@ -1137,7 +1129,7 @@ void node::incoming_request(msg const& m, entry& e) // , msg_keys[1] ? "mutable":"immutable" // , aux::to_hex(target.to_string()).c_str()); - reply["token"] = generate_token(m.addr, msg_keys[1].string_ptr()); + reply["token"] = generate_token(m.addr, sha1_hash(msg_keys[1].string_ptr())); // always return nodes as well as peers write_nodes_entries(target, msg_keys[2], reply); @@ -1148,13 +1140,14 @@ void node::incoming_request(msg const& m, entry& e) { if (!m_storage.get_immutable_item(target, reply)) // ok, check for a mutable one { - m_storage.get_mutable_item(target, 0, true, reply); + m_storage.get_mutable_item(target, sequence_number(0) + , true, reply); } } else { m_storage.get_mutable_item(target - , msg_keys[0].int_value(), false + , sequence_number(msg_keys[0].int_value()), false , reply); } } diff --git a/src/kademlia/put_data.cpp b/src/kademlia/put_data.cpp index 00f74ffc3..659634d96 100644 --- a/src/kademlia/put_data.cpp +++ b/src/kademlia/put_data.cpp @@ -106,9 +106,9 @@ bool put_data::invoke(observer_ptr o) a["token"] = po->m_token; if (m_data.is_mutable()) { - a["k"] = std::string(m_data.pk().data(), item_pk_len); - a["seq"] = m_data.seq(); - a["sig"] = std::string(m_data.sig().data(), item_sig_len); + a["k"] = m_data.pk().bytes; + a["seq"] = m_data.seq().value; + a["sig"] = m_data.sig().bytes; if (!m_data.salt().empty()) { a["salt"] = m_data.salt(); diff --git a/src/pe_crypto.cpp b/src/pe_crypto.cpp index f4a201380..0d32297ea 100644 --- a/src/pe_crypto.cpp +++ b/src/pe_crypto.cpp @@ -96,11 +96,9 @@ namespace libtorrent std::array buffer; mp::export_bits(m_dh_shared_secret, reinterpret_cast(buffer.data()), 8); + static char const req3[4] = {'r', 'e', 'q', '3'}; // calculate the xor mask for the obfuscated hash - hasher h; - h.update("req3", 4); - h.update(buffer); - m_xor_mask = h.final(); + m_xor_mask = hasher(req3).update(buffer).final(); } std::tuple> @@ -148,7 +146,7 @@ namespace libtorrent if (num_bufs != 0) { std::tie(next_barrier, out_iovec) - = m_send_barriers.front().enc_handler->encrypt({bufs, num_bufs}); + = m_send_barriers.front().enc_handler->encrypt({bufs, size_t(num_bufs)}); } if (m_send_barriers.front().next != INT_MAX) diff --git a/src/read_resume_data.cpp b/src/read_resume_data.cpp index a0d8590ba..cec5fbf28 100644 --- a/src/read_resume_data.cpp +++ b/src/read_resume_data.cpp @@ -97,8 +97,7 @@ namespace libtorrent { // verify the info-hash of the metadata stored in the resume file matches // the torrent we're loading - sha1_hash const resume_ih = hasher(info.data_section().first - , info.data_section().second).final(); + sha1_hash const resume_ih = hasher(info.data_section()).final(); // if url is set, the info_hash is not actually the info-hash of the // torrent, but the hash of the URL, until we have the full torrent diff --git a/src/session_handle.cpp b/src/session_handle.cpp index 118854757..380e4b66e 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -521,6 +521,8 @@ namespace libtorrent #endif } + // TODO: 3 expose the sequence_number, public_key, secret_key and signature + // types to the client sha1_hash session_handle::dht_put_item(entry data) { std::vector buf; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index dc8707dce..e2ca98b94 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -81,6 +81,7 @@ const rlim_t rlim_infinity = RLIM_INFINITY; #include "libtorrent/aux_/session_impl.hpp" #ifndef TORRENT_DISABLE_DHT #include "libtorrent/kademlia/dht_tracker.hpp" +#include "libtorrent/kademlia/types.hpp" #endif #include "libtorrent/enum_net.hpp" #include "libtorrent/config.hpp" @@ -4716,9 +4717,9 @@ namespace aux { TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size()); #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) - hasher h; - h.update("req2", 4); - h.update(params.info_hash.data(), 20); + static char const req2[4] = {'r', 'e', 'q', '2'}; + hasher h(req2); + h.update(params.info_hash); // this is SHA1("req2" + info-hash), used for // encrypted hand shakes m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr)); @@ -5044,8 +5045,7 @@ namespace aux { if (i == m_torrents.end() && !tptr->url().empty()) { std::string const& url = tptr->url(); - sha1_hash urlhash = hasher(&url[0], int(url.size())).final(); - i = m_torrents.find(urlhash); + i = m_torrents.find(hasher(url).final()); } #endif @@ -5085,9 +5085,9 @@ namespace aux { TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size()); #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) - hasher h; - h.update("req2", 4); - h.update(tptr->info_hash().data(), 20); + static char const req2[4] = {'r', 'e', 'q', '2'}; + hasher h(req2); + h.update(tptr->info_hash()); m_obfuscated_torrents.erase(h.final()); #endif @@ -5714,20 +5714,23 @@ namespace aux { } // callback for dht_mutable_get - void session_impl::get_mutable_callback(dht::item const& i, bool authoritative) + void session_impl::get_mutable_callback(dht::item const& i + , bool const authoritative) { TORRENT_ASSERT(i.is_mutable()); - m_alerts.emplace_alert(i.pk(), i.sig(), i.seq() + m_alerts.emplace_alert(i.pk().bytes + , i.sig().bytes, i.seq().value , i.salt(), i.value(), authoritative); } // key is a 32-byte binary string, the public key to look up. // the salt is optional + // TODO: 3 use public_key here instead of std::array void session_impl::dht_get_mutable_item(std::array key , std::string salt) { if (!m_dht) return; - m_dht->get_item(key.data(), std::bind(&session_impl::get_mutable_callback + m_dht->get_item(dht::public_key(key.data()), std::bind(&session_impl::get_mutable_callback , this, _1, _2), salt); } @@ -5741,26 +5744,29 @@ namespace aux { void on_dht_put_mutable_item(alert_manager& alerts, dht::item const& i, int num) { - std::array sig = i.sig(); - std::array pk = i.pk(); - std::uint64_t seq = i.seq(); + dht::signature sig = i.sig(); + dht::public_key pk = i.pk(); + dht::sequence_number seq = i.seq(); std::string salt = i.salt(); if (alerts.should_post()) - alerts.emplace_alert(pk, sig, salt, seq, num); + { + alerts.emplace_alert(pk.bytes, sig.bytes, salt + , seq.value, num); + } } void put_mutable_callback(dht::item& i - , boost::function& + , boost::function& , std::uint64_t&, std::string const&)> cb) { entry value = i.value(); - std::array sig = i.sig(); - std::array pk = i.pk(); - std::uint64_t seq = i.seq(); + dht::signature sig = i.sig(); + dht::public_key pk = i.pk(); + dht::sequence_number seq = i.seq(); std::string salt = i.salt(); - cb(value, sig, seq, salt); - i.assign(value, salt, seq, pk.data(), sig.data()); + cb(value, sig.bytes, seq.value, salt); + i.assign(std::move(value), salt, seq, pk, sig); } void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector const& peers) @@ -5792,9 +5798,9 @@ namespace aux { , std::string salt) { if (!m_dht) return; - m_dht->put_item(key.data(), - std::bind(&on_dht_put_mutable_item, boost::ref(m_alerts), _1, _2), - std::bind(&put_mutable_callback, _1, cb), salt); + m_dht->put_item(dht::public_key(key.data()) + , std::bind(&on_dht_put_mutable_item, boost::ref(m_alerts), _1, _2) + , std::bind(&put_mutable_callback, _1, cb), salt); } void session_impl::dht_get_peers(sha1_hash const& info_hash) diff --git a/src/smart_ban.cpp b/src/smart_ban.cpp index 0ae992217..a8784d770 100644 --- a/src/smart_ban.cpp +++ b/src/smart_ban.cpp @@ -195,7 +195,7 @@ namespace h.update(j->buffer.disk_block, j->d.io.buffer_size); h.update(reinterpret_cast(&m_salt), sizeof(m_salt)); - std::pair range + std::pair const range = m_torrent.find_peers(a); // there is no peer with this address anymore @@ -270,7 +270,7 @@ namespace hasher h; h.update(j->buffer.disk_block, j->d.io.buffer_size); h.update(reinterpret_cast(&m_salt), sizeof(m_salt)); - sha1_hash ok_digest = h.final(); + sha1_hash const ok_digest = h.final(); if (b.second.digest == ok_digest) return; diff --git a/src/torrent.cpp b/src/torrent.cpp index d37ebbd9f..1c97324ab 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -537,8 +537,8 @@ namespace libtorrent m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end()); #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) - hasher h; - h.update("req2", 4); + static char const req2[4] = {'r', 'e', 'q', '2'}; + hasher h(req2); h.update(m_torrent_file->info_hash()); m_ses.add_obfuscated_hash(h.final(), shared_from_this()); #endif @@ -7011,6 +7011,7 @@ namespace libtorrent return peerinfo->connection != nullptr; } + // TODO: 3 make this take a span instead bool torrent::set_metadata(char const* metadata_buf, int metadata_size) { TORRENT_ASSERT(is_single_thread()); @@ -7031,7 +7032,8 @@ namespace libtorrent bdecode_node metadata; error_code ec; - int ret = bdecode(metadata_buf, metadata_buf + metadata_size, metadata, ec); + int ret = bdecode(metadata_buf + , metadata_buf + metadata_size, metadata, ec); if (ret != 0 || !m_torrent_file->parse_info_section(metadata, ec, 0)) { update_gauge(); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 974e4a5fd..b9c9a87e2 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -1050,28 +1050,25 @@ namespace libtorrent } // hash the info-field to calculate info-hash - hasher h; - std::pair section = info.data_section(); - h.update(section.first, section.second); - m_info_hash = h.final(); - - if (section.second >= (std::numeric_limits::max)()) + auto section = info.data_section(); + m_info_hash = hasher(section).final(); + if (info.data_section().size() >= (std::numeric_limits::max)()) { ec = errors::metadata_too_large; return false; } // copy the info section - m_info_section_size = section.second; + m_info_section_size = int(section.size()); m_info_section.reset(new char[m_info_section_size]); - std::memcpy(m_info_section.get(), section.first, m_info_section_size); - TORRENT_ASSERT(section.first[0] == 'd'); - TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e'); + std::memcpy(m_info_section.get(), section.data(), m_info_section_size); + TORRENT_ASSERT(section[0] == 'd'); + TORRENT_ASSERT(section[m_info_section_size-1] == 'e'); // when translating a pointer that points into the 'info' tree's // backing buffer, into a pointer to our copy of the info section, // this is the pointer offset to use. - ptrdiff_t info_ptr_diff = m_info_section.get() - section.first; + ptrdiff_t const info_ptr_diff = m_info_section.get() - section.data(); // extract piece length int piece_length = info.dict_find_int_value("piece length", -1); diff --git a/test/Jamfile b/test/Jamfile index e27a48fb7..184fccd7b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -143,6 +143,7 @@ test-suite libtorrent : [ run test_dht.cpp test_dht_storage.cpp + test_direct_dht.cpp ] [ run test_string.cpp @@ -154,7 +155,6 @@ test-suite libtorrent : [ run test_crc32.cpp ] [ run test_receive_buffer.cpp ] [ run test_alert_manager.cpp ] - [ run test_direct_dht.cpp ] [ run test_magnet.cpp ] [ run test_storage.cpp ] [ run test_session.cpp ] diff --git a/test/test_bdecode.cpp b/test/test_bdecode.cpp index 4e27e31c8..742f955cc 100644 --- a/test/test_bdecode.cpp +++ b/test/test_bdecode.cpp @@ -42,13 +42,13 @@ TORRENT_TEST(integer) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); - std::pair section = e.data_section(); - TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); - TEST_CHECK(section.second == sizeof(b) - 1); - TEST_CHECK(e.type() == bdecode_node::int_t); - TEST_CHECK(e.int_value() == 12453); + span section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), sizeof(b) - 1); + TEST_EQUAL(e.type(), bdecode_node::int_t); + TEST_EQUAL(e.int_value(), 12453); } // test string @@ -58,11 +58,11 @@ TORRENT_TEST(string) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); - std::pair section = e.data_section(); - TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); - TEST_EQUAL(section.second, sizeof(b) - 1); + span section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), sizeof(b) - 1); TEST_EQUAL(e.type(), bdecode_node::string_t); TEST_EQUAL(e.string_value(), std::string("abcdefghijklmnopqrstuvwxyz")); TEST_EQUAL(e.string_length(), 26); @@ -79,11 +79,11 @@ TORRENT_TEST(string_prefix1) bdecode_node e; error_code ec; int ret = bdecode(test.c_str(), test.c_str() + test.size(), e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%d bytes string\n", e.string_length()); - std::pair section = e.data_section(); - TEST_CHECK(std::memcmp(test.c_str(), section.first, section.second) == 0); - TEST_EQUAL(section.second, int(test.size())); + span section = e.data_section(); + TEST_CHECK(std::memcmp(test.c_str(), section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), test.size()); TEST_EQUAL(e.type(), bdecode_node::string_t); TEST_EQUAL(e.string_length(), 1000000); TEST_EQUAL(e.string_ptr(), test.c_str() + 8); @@ -96,21 +96,21 @@ TORRENT_TEST(list) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); - std::pair section = e.data_section(); - TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); - TEST_CHECK(section.second == sizeof(b) - 1); - TEST_CHECK(e.type() == bdecode_node::list_t); - TEST_CHECK(e.list_size() == 2); - TEST_CHECK(e.list_at(0).type() == bdecode_node::int_t); - TEST_CHECK(e.list_at(1).type() == bdecode_node::string_t); - TEST_CHECK(e.list_at(0).int_value() == 12453); - TEST_CHECK(e.list_at(1).string_value() == std::string("aaa")); - TEST_CHECK(e.list_at(1).string_length() == 3); + span section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), sizeof(b) - 1); + TEST_EQUAL(e.type(), bdecode_node::list_t); + TEST_EQUAL(e.list_size(), 2); + TEST_EQUAL(e.list_at(0).type(), bdecode_node::int_t); + TEST_EQUAL(e.list_at(1).type(), bdecode_node::string_t); + TEST_EQUAL(e.list_at(0).int_value(), 12453); + TEST_EQUAL(e.list_at(1).string_value(), std::string("aaa")); + TEST_EQUAL(e.list_at(1).string_length(), 3); section = e.list_at(1).data_section(); - TEST_CHECK(std::memcmp("3:aaa", section.first, section.second) == 0); - TEST_CHECK(section.second == 5); + TEST_CHECK(std::memcmp("3:aaa", section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), 5); } // test dict @@ -122,20 +122,20 @@ TORRENT_TEST(dict) int ret = bdecode(b, b + sizeof(b)-1, e, ec); TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); - std::pair section = e.data_section(); - TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); - TEST_CHECK(section.second == sizeof(b) - 1); - TEST_CHECK(e.type() == bdecode_node::dict_t); - TEST_CHECK(e.dict_size() == 4); - TEST_CHECK(e.dict_find("a").type() == bdecode_node::int_t); - TEST_CHECK(e.dict_find("a").int_value() == 12453); - TEST_CHECK(e.dict_find("b").type() == bdecode_node::string_t); - TEST_CHECK(e.dict_find("b").string_value() == std::string("aaa")); - TEST_CHECK(e.dict_find("b").string_length() == 3); - TEST_CHECK(e.dict_find("c").type() == bdecode_node::string_t); - TEST_CHECK(e.dict_find("c").string_value() == std::string("bbb")); - TEST_CHECK(e.dict_find("c").string_length() == 3); - TEST_CHECK(e.dict_find_string_value("X") == "0123456789"); + span section = e.data_section(); + TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0); + TEST_EQUAL(section.size(), sizeof(b) - 1); + TEST_EQUAL(e.type(), bdecode_node::dict_t); + TEST_EQUAL(e.dict_size(), 4); + TEST_EQUAL(e.dict_find("a").type(), bdecode_node::int_t); + TEST_EQUAL(e.dict_find("a").int_value(), 12453); + TEST_EQUAL(e.dict_find("b").type(), bdecode_node::string_t); + TEST_EQUAL(e.dict_find("b").string_value(), std::string("aaa")); + TEST_EQUAL(e.dict_find("b").string_length(), 3); + TEST_EQUAL(e.dict_find("c").type(), bdecode_node::string_t); + TEST_EQUAL(e.dict_find("c").string_value(), std::string("bbb")); + TEST_EQUAL(e.dict_find("c").string_length(), 3); + TEST_EQUAL(e.dict_find_string_value("X"), "0123456789"); } // test dictionary with a key without a value @@ -173,7 +173,7 @@ TORRENT_TEST(dict_null_key) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); TEST_CHECK(e.dict_size() == 1); bdecode_node d = e.dict_find(std::string("a\0b", 3)); TEST_EQUAL(d.type(), bdecode_node::int_t); @@ -350,7 +350,7 @@ TORRENT_TEST(64bit_int) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); TEST_CHECK(e.int_value() == 9223372036854775807LL); } @@ -362,7 +362,7 @@ TORRENT_TEST(64bit_int_negative) bdecode_node e; error_code ec; int ret = bdecode(b, b + sizeof(b)-1, e, ec); - TEST_CHECK(ret == 0); + TEST_EQUAL(ret, 0); std::printf("%s\n", print_entry(e).c_str()); TEST_CHECK(e.int_value() == -9223372036854775807LL); } diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 5a8c33895..6c09a6fdd 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -70,11 +70,21 @@ sha1_hash to_hash(char const* s) return ret; } -void get_test_keypair(char* public_key, char* private_key) +void get_test_keypair(public_key& pk, secret_key& sk) { - aux::from_hex("77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548", 64, public_key); + aux::from_hex("77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548", 64, pk.bytes.data()); aux::from_hex("e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74d" - "b7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d", 128, private_key); + "b7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d", 128, sk.bytes.data()); +} + +sequence_number prev_seq(sequence_number s) +{ + return sequence_number(s.value - 1); +} + +sequence_number next_seq(sequence_number s) +{ + return sequence_number(s.value + 1); } void add_and_replace(libtorrent::dht::node_id& dst, libtorrent::dht::node_id const& add) @@ -163,8 +173,8 @@ struct msg_args msg_args& port(int p) { a["port"] = p; return *this; } - msg_args& target(char const* t) - { if (t) a["target"] = std::string(t, 20); return *this; } + msg_args& target(sha1_hash const& t) + { a["target"] = t.to_string(); return *this; } msg_args& value(entry const& v) { a["v"] = v; return *this; } @@ -175,23 +185,23 @@ struct msg_args msg_args& seed(bool s) { a["seed"] = s ? 1 : 0; return *this; } - msg_args& key(std::string k) - { a["k"] = k; return *this; } + msg_args& key(public_key const& k) + { a["k"] = k.bytes; return *this; } - msg_args& sig(std::string s) - { a["sig"] = s; return *this; } + msg_args& sig(signature const& s) + { a["sig"] = s.bytes; return *this; } - msg_args& seq(int s) - { a["seq"] = s; return *this; } + msg_args& seq(sequence_number s) + { a["seq"] = s.value; return *this; } - msg_args& cas(std::int64_t c) - { a["cas"] = c; return *this; } + msg_args& cas(sequence_number c) + { a["cas"] = c.value; return *this; } msg_args& nid(sha1_hash const& n) { a["id"] = n.to_string(); return *this; } - msg_args& salt(char const* s) - { if (s) a["salt"] = s; return *this; } + msg_args& salt(span s) + { if (!s.empty()) a["salt"] = s; return *this; } msg_args& want(std::string w) { a["want"].list().push_back(w); return *this; } @@ -312,7 +322,7 @@ void announce_immutable_items(node& node, udp::endpoint const* eps if ((i % items[j].num_peers) == 0) continue; bdecode_node response; send_dht_request(node, "get", eps[i], &response - , msg_args().target((char const*)&items[j].target[0])); + , msg_args().target(items[j].target)); key_desc_t const desc[] = { @@ -353,7 +363,7 @@ void announce_immutable_items(node& node, udp::endpoint const* eps send_dht_request(node, "put", eps[i], &response , msg_args() .token(token) - .target((char const*)&items[j].target[0]) + .target(items[j].target) .value(items[j].ent)); key_desc_t const desc2[] = @@ -385,7 +395,7 @@ void announce_immutable_items(node& node, udp::endpoint const* eps { bdecode_node response; send_dht_request(node, "get", eps[j], &response - , msg_args().target((char const*)&items[j].target[0])); + , msg_args().target(items[j].target)); key_desc_t const desc[] = { @@ -554,9 +564,9 @@ dht::key_desc_t const put_mutable_item_desc[] = { {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children}, {"id", bdecode_node::string_t, 20, 0}, {"cas", bdecode_node::string_t, 20, key_desc_t::optional}, - {"k", bdecode_node::string_t, item_pk_len, 0}, + {"k", bdecode_node::string_t, public_key::len, 0}, {"seq", bdecode_node::int_t, 0, 0}, - {"sig", bdecode_node::string_t, item_sig_len, 0}, + {"sig", bdecode_node::string_t, signature::len, 0}, {"token", bdecode_node::string_t, 2, 0}, {"v", bdecode_node::none_t, 0, key_desc_t::last_child}, }; @@ -820,7 +830,9 @@ void test_id_enforcement(address(&rand_addr)()) nid[0] = 0x18; int nodes_num = std::get<0>(t.dht_node.size()); send_dht_request(t.dht_node, "find_node", t.source, &response - , msg_args().target("0101010101010101010101010101010101010101").nid(nid)); + , msg_args() + .target(sha1_hash("0101010101010101010101010101010101010101")) + .nid(nid)); bdecode_node err_keys[2]; bool ret = dht::verify_message(response, err_desc, err_keys, t.error_string @@ -855,7 +867,9 @@ void test_id_enforcement(address(&rand_addr)()) else nid[0] = 0x0a; send_dht_request(t.dht_node, "find_node", t.source, &response - , msg_args().target("0101010101010101010101010101010101010101").nid(nid)); + , msg_args() + .target(sha1_hash("0101010101010101010101010101010101010101")) + .nid(nid)); dht::key_desc_t const nodes_desc[] = { {"y", bdecode_node::string_t, 1, 0}, @@ -981,7 +995,7 @@ namespace { return nodes; } - std::pair const empty_salt(nullptr, 0); + span const empty_salt; } // TODO: 3 split this up into smaller tests @@ -1018,41 +1032,42 @@ void test_put(address(&rand_addr)()) // ==== get / put mutable items === - std::pair itemv; + span itemv; - char signature[item_sig_len]; + signature sig; char buffer[1200]; - int seq = 4; - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); + sequence_number seq(4); + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); + // TODO: 4 pass in the actual salt as a parameter for (int with_salt = 0; with_salt < 2; ++with_salt) { - seq = 4; + seq = sequence_number(4); std::fprintf(stderr, "\nTEST GET/PUT%s \ngenerating ed25519 keys\n\n" , with_salt ? " with-salt" : " no-salt"); unsigned char seed[32]; ed25519_create_seed(seed); - ed25519_create_keypair((unsigned char*)public_key, (unsigned char*)private_key, seed); + ed25519_create_keypair((unsigned char*)pk.bytes.data() + , (unsigned char*)sk.bytes.data(), seed); std::fprintf(stderr, "pub: %s priv: %s\n" - , aux::to_hex(std::string(public_key, item_pk_len)).c_str() - , aux::to_hex(std::string(private_key, item_sk_len)).c_str()); + , aux::to_hex(std::string(pk.bytes.data(), public_key::len)).c_str() + , aux::to_hex(std::string(sk.bytes.data(), secret_key::len)).c_str()); - std::pair salt(nullptr, 0); - if (with_salt) - salt = std::pair("foobar", 6); + std::string salt; + if (with_salt) salt = "foobar"; - hasher h(public_key, 32); - if (with_salt) h.update(salt.first, salt.second); + hasher h(pk.bytes); + if (with_salt) h.update(salt); sha1_hash target_id = h.final(); std::fprintf(stderr, "target_id: %s\n" , aux::to_hex(target_id.to_string()).c_str()); send_dht_request(t.dht_node, "get", t.source, &response - , msg_args().target((char*)&target_id[0])); + , msg_args().target(target_id)); key_desc_t const desc[] = { @@ -1084,18 +1099,18 @@ void test_put(address(&rand_addr)()) TEST_ERROR(t.error_string); } - itemv = std::pair(buffer, bencode(buffer, items[0].ent)); - sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); - TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), true); + itemv = span(buffer, bencode(buffer, items[0].ent)); + sign_mutable_item(itemv, salt, seq, pk, sk, sig); + TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), true); send_dht_request(t.dht_node, "put", t.source, &response , msg_args() .token(token) .value(items[0].ent) - .key(std::string(public_key, item_pk_len)) - .sig(std::string(signature, item_sig_len)) + .key(pk) + .sig(sig) .seq(seq) - .salt(salt.first)); + .salt(salt)); ret = verify_message(response, desc2, desc2_keys, t.error_string , sizeof(t.error_string)); @@ -1113,7 +1128,7 @@ void test_put(address(&rand_addr)()) } send_dht_request(t.dht_node, "get", t.source, &response - , msg_args().target((char*)&target_id[0])); + , msg_args().target(target_id)); std::fprintf(stderr, "target_id: %s\n" , aux::to_hex(target_id.to_string()).c_str()); @@ -1146,33 +1161,33 @@ void test_put(address(&rand_addr)()) , print_entry(response).c_str()); char value[1020]; char* ptr = value; - int value_len = bencode(ptr, items[0].ent); - TEST_EQUAL(value_len, desc3_keys[2].data_section().second); - TEST_CHECK(memcmp(desc3_keys[2].data_section().first, value, value_len) == 0); + int const value_len = bencode(ptr, items[0].ent); + TEST_EQUAL(value_len, int(desc3_keys[2].data_section().size())); + TEST_CHECK(memcmp(desc3_keys[2].data_section().data(), value, value_len) == 0); - TEST_EQUAL(seq, desc3_keys[3].int_value()); + TEST_EQUAL(int(seq.value), desc3_keys[3].int_value()); } // also test that invalid signatures fail! - itemv = std::pair(buffer, bencode(buffer, items[0].ent)); - sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); - TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), 1); + itemv = span(buffer, bencode(buffer, items[0].ent)); + sign_mutable_item(itemv, salt, seq, pk, sk, sig); + TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), 1); // break the signature - signature[2] ^= 0xaa; + sig.bytes[2] ^= 0xaa; std::fprintf(stderr, "PUT broken signature\n"); - TEST_CHECK(verify_mutable_item(itemv, salt, seq, public_key, signature) != 1); + TEST_CHECK(verify_mutable_item(itemv, salt, seq, pk, sig) != 1); send_dht_request(t.dht_node, "put", t.source, &response , msg_args() .token(token) .value(items[0].ent) - .key(std::string(public_key, item_pk_len)) - .sig(std::string(signature, item_sig_len)) + .key(pk) + .sig(sig) .seq(seq) - .salt(salt.first)); + .salt(salt)); ret = verify_message(response, desc_error, desc_error_keys, t.error_string , sizeof(t.error_string)); @@ -1193,7 +1208,7 @@ void test_put(address(&rand_addr)()) // === test conditional get === send_dht_request(t.dht_node, "get", t.source, &response - , msg_args().target((char*)&target_id[0]).seq(seq - 1)); + , msg_args().target(target_id).seq(prev_seq(seq))); { bdecode_node const r = response.dict_find_dict("r"); @@ -1203,7 +1218,7 @@ void test_put(address(&rand_addr)()) } send_dht_request(t.dht_node, "get", t.source, &response - , msg_args().target((char*)&target_id[0]).seq(seq)); + , msg_args().target(target_id).seq(seq)); { bdecode_node r = response.dict_find_dict("r"); @@ -1215,16 +1230,16 @@ void test_put(address(&rand_addr)()) // === test CAS put === // this is the sequence number we expect to be there - std::uint64_t cas = seq; + sequence_number cas = seq; // increment sequence number - ++seq; + seq = next_seq(seq); // put item 1 - itemv = std::pair(buffer, bencode(buffer, items[1].ent)); - sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); - TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), 1); + itemv = span(buffer, bencode(buffer, items[1].ent)); + sign_mutable_item(itemv, salt, seq, pk, sk, sig); + TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), 1); - TEST_CHECK(item_target_id(salt, public_key) == target_id); + TEST_CHECK(item_target_id(salt, pk) == target_id); std::fprintf(stderr, "PUT CAS 1\n"); @@ -1232,11 +1247,11 @@ void test_put(address(&rand_addr)()) , msg_args() .token(token) .value(items[1].ent) - .key(std::string(public_key, item_pk_len)) - .sig(std::string(signature, item_sig_len)) + .key(pk) + .sig(sig) .seq(seq) .cas(cas) - .salt(salt.first)); + .salt(salt)); ret = verify_message(response, desc2, desc2_keys, t.error_string , sizeof(t.error_string)); @@ -1262,11 +1277,11 @@ void test_put(address(&rand_addr)()) , msg_args() .token(token) .value(items[1].ent) - .key(std::string(public_key, item_pk_len)) - .sig(std::string(signature, item_sig_len)) + .key(pk) + .sig(sig) .seq(seq) .cas(cas) - .salt(salt.first)); + .salt(salt)); ret = verify_message(response, desc_error, desc_error_keys, t.error_string , sizeof(t.error_string)); @@ -1767,23 +1782,22 @@ TORRENT_TEST(get_peers_v6) } #endif +// TODO: 4 pass in th actual salt as the argument void test_mutable_get(address(&rand_addr)(), bool const with_salt) { dht_test_setup t(udp::endpoint(rand_addr(), 20)); - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); - char signature[item_sig_len]; char buffer[1200]; - int seq = 4; - std::pair itemv; + sequence_number seq(4); + span itemv; bdecode_node response; - std::pair salt(nullptr, 0); - if (with_salt) - salt = std::pair("foobar", 6); + std::string salt; + if (with_salt) salt = "foobar"; // mutable get @@ -1792,9 +1806,8 @@ void test_mutable_get(address(&rand_addr)(), bool const with_salt) udp::endpoint const initial_node(rand_addr(), 1234); t.dht_node.m_table.add_node(initial_node); - g_put_item.assign(items[0].ent, salt, seq, public_key, private_key); - std::string sig(g_put_item.sig().data(), item_sig_len); - t.dht_node.put_item(public_key, std::string() + g_put_item.assign(items[0].ent, salt, seq, pk, sk); + t.dht_node.put_item(pk, std::string() , std::bind(&put_mutable_item_cb, _1, _2, 0) , put_mutable_item_data_cb); @@ -1804,7 +1817,7 @@ void test_mutable_get(address(&rand_addr)(), bool const with_salt) g_sent_packets.clear(); - t.dht_node.get_item(public_key, std::string(salt.first, salt.second), get_mutable_item_cb); + t.dht_node.get_item(pk, salt, get_mutable_item_cb); TEST_EQUAL(g_sent_packets.size(), 1); if (g_sent_packets.empty()) return; @@ -1831,16 +1844,17 @@ void test_mutable_get(address(&rand_addr)(), bool const with_salt) g_sent_packets.clear(); - itemv = std::pair(buffer, bencode(buffer, items[0].ent)); - sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); + signature sig; + itemv = span(buffer, bencode(buffer, items[0].ent)); + sign_mutable_item(itemv, salt, seq, pk, sk, sig); send_dht_response(t.dht_node, response, initial_node , msg_args() .token("10") .port(1234) .value(items[0].ent) - .key(std::string(public_key, item_pk_len)) - .sig(std::string(signature, item_sig_len)) - .salt(salt.first) + .key(pk) + .sig(sig) + .salt(salt) .seq(seq)); TEST_CHECK(g_sent_packets.empty()); @@ -1848,9 +1862,9 @@ void test_mutable_get(address(&rand_addr)(), bool const with_salt) if (g_got_items.empty()) return; TEST_EQUAL(g_got_items.front().value(), items[0].ent); - TEST_CHECK(memcmp(g_got_items.front().pk().data(), public_key, item_pk_len) == 0); - TEST_CHECK(memcmp(g_got_items.front().sig().data(), signature, item_sig_len) == 0); - TEST_EQUAL(int(g_got_items.front().seq()), seq); + TEST_CHECK(g_got_items.front().pk() == pk); + TEST_CHECK(g_got_items.front().sig() == sig); + TEST_CHECK(g_got_items.front().seq() == seq); g_got_items.clear(); } @@ -1929,7 +1943,7 @@ TORRENT_TEST(immutable_get) TORRENT_TEST(immutable_put) { bdecode_node response; - std::pair itemv; + span itemv; char buffer[1200]; dht::key_desc_t const put_immutable_item_desc[] = { @@ -1963,7 +1977,7 @@ TORRENT_TEST(immutable_put) std::string flat_data; bencode(std::back_inserter(flat_data), put_data); sha1_hash target = item_target_id( - std::pair(flat_data.c_str(), int(flat_data.size()))); + span(flat_data.c_str(), int(flat_data.size()))); t.dht_node.put_item(target, put_data, std::bind(&put_immutable_item_cb, _1, loop)); @@ -1998,7 +2012,7 @@ TORRENT_TEST(immutable_put) TEST_EQUAL(g_sent_packets.size(), 8); if (g_sent_packets.size() != 8) break; - itemv = std::pair(buffer, bencode(buffer, put_data)); + itemv = span(buffer, bencode(buffer, put_data)); for (int i = 0; i < 8; ++i) { @@ -2013,8 +2027,8 @@ TORRENT_TEST(immutable_put) { TEST_EQUAL(put_immutable_item_keys[0].string_value(), "q"); TEST_EQUAL(put_immutable_item_keys[2].string_value(), "put"); - std::pair v = put_immutable_item_keys[6].data_section(); - TEST_EQUAL(std::string(v.first, v.second), flat_data); + span v = put_immutable_item_keys[6].data_section(); + TEST_EQUAL(std::string(v.data(), v.size()), flat_data); char tok[10]; std::snprintf(tok, sizeof(tok), "%02d", i); TEST_EQUAL(put_immutable_item_keys[5].string_value(), tok); @@ -2039,14 +2053,14 @@ TORRENT_TEST(immutable_put) TORRENT_TEST(mutable_put) { bdecode_node response; - std::pair itemv; + span itemv; char buffer[1200]; bdecode_node put_mutable_item_keys[11]; - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); - int seq = 4; + sequence_number seq(4); // mutable put g_sent_packets.clear(); @@ -2063,9 +2077,9 @@ TORRENT_TEST(mutable_put) for (int i = 0; i < num_test_nodes; ++i) t.dht_node.m_table.add_node(nodes[i]); - g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key); - std::string sig(g_put_item.sig().data(), item_sig_len); - t.dht_node.put_item(public_key, std::string() + g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk); + signature const sig = g_put_item.sig(); + t.dht_node.put_item(pk, std::string() , std::bind(&put_mutable_item_cb, _1, _2, loop) , put_mutable_item_data_cb); @@ -2100,7 +2114,7 @@ TORRENT_TEST(mutable_put) TEST_EQUAL(g_sent_packets.size(), 8); if (g_sent_packets.size() != 8) break; - itemv = std::pair(buffer, bencode(buffer, items[0].ent)); + itemv = span(buffer, bencode(buffer, items[0].ent)); for (int i = 0; i < 8; ++i) { @@ -2115,12 +2129,12 @@ TORRENT_TEST(mutable_put) { TEST_EQUAL(put_mutable_item_keys[0].string_value(), "q"); TEST_EQUAL(put_mutable_item_keys[2].string_value(), "put"); - TEST_EQUAL(put_mutable_item_keys[6].string_value(), std::string(public_key, item_pk_len)); - TEST_EQUAL(put_mutable_item_keys[7].int_value(), seq); - TEST_EQUAL(put_mutable_item_keys[8].string_value(), sig); - std::pair v = put_mutable_item_keys[10].data_section(); - TEST_EQUAL(v.second, itemv.second); - TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); + TEST_EQUAL(put_mutable_item_keys[6].string_value(), std::string(pk.bytes.data(), public_key::len)); + TEST_EQUAL(put_mutable_item_keys[7].int_value(), int(seq.value)); + TEST_EQUAL(put_mutable_item_keys[8].string_value(), std::string(sig.bytes.data(), signature::len)); + span v = put_mutable_item_keys[10].data_section(); + TEST_EQUAL(v.size(), itemv.size()); + TEST_CHECK(memcmp(v.data(), itemv.data(), itemv.size()) == 0); char tok[10]; std::snprintf(tok, sizeof(tok), "%02d", i); TEST_EQUAL(put_mutable_item_keys[9].string_value(), tok); @@ -2149,18 +2163,18 @@ TORRENT_TEST(traversal_done) // set the branching factor to k to make this a little easier t.sett.search_branching = 8; - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); - int seq = 4; + sequence_number seq(4); bdecode_node response; // verify that done() is only invoked once // See PR 252 g_sent_packets.clear(); - sha1_hash target = hasher(public_key, item_pk_len).final(); + sha1_hash const target = hasher(pk.bytes).final(); enum { num_test_nodes = 9 }; // we need K + 1 nodes to create the failing sequence std::array nodes = build_nodes(target); @@ -2175,8 +2189,8 @@ TORRENT_TEST(traversal_done) t.dht_node.m_table.add_node(nodes[i]); // kick off a mutable put request - g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key); - t.dht_node.put_item(public_key, std::string() + g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk); + t.dht_node.put_item(pk, std::string() , std::bind(&put_mutable_item_cb, _1, _2, 0) , put_mutable_item_data_cb); TEST_EQUAL(g_sent_packets.size(), 8); @@ -2259,7 +2273,9 @@ TORRENT_TEST(dht_dual_stack) udp::endpoint source(addr("10.0.0.1"), 20); send_dht_request(node4, "find_node", source, &response - , msg_args().target("0101010101010101010101010101010101010101").want("n6")); + , msg_args() + .target(sha1_hash("0101010101010101010101010101010101010101")) + .want("n6")); dht::key_desc_t const nodes6_desc[] = { { "y", bdecode_node::string_t, 1, 0 }, @@ -2366,50 +2382,47 @@ TORRENT_TEST(signing_test1) // test vector 1 // test content - std::pair test_content("12:Hello World!", 15); + span test_content("12:Hello World!", 15); // test salt - std::pair test_salt("foobar", 6); + span test_salt("foobar", 6); - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); - std::pair empty_salt; + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); + span empty_salt; - char signature[item_sig_len]; + signature sig; + sign_mutable_item(test_content, empty_salt, sequence_number(1), pk, sk, sig); - sign_mutable_item(test_content, empty_salt, 1, public_key - , private_key, signature); - - TEST_EQUAL(aux::to_hex(std::string(signature, 64)) + TEST_EQUAL(aux::to_hex(std::string(sig.bytes.data(), signature::len)) , "305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff" "1260d3f39e4999684aa92eb73ffd136e6f4f3ecbfda0ce53a1608ecd7ae21f01"); - sha1_hash target_id = item_target_id(empty_salt, public_key); + sha1_hash target_id = item_target_id(empty_salt, pk); TEST_EQUAL(aux::to_hex(target_id.to_string()), "4a533d47ec9c7d95b1ad75f576cffc641853b750"); } TORRENT_TEST(signing_test2) { - char public_key[item_pk_len]; - char private_key[item_sk_len]; - get_test_keypair(public_key, private_key); + public_key pk; + secret_key sk; + get_test_keypair(pk, sk); // test content - std::pair test_content("12:Hello World!", 15); + span test_content("12:Hello World!", 15); - char signature[item_sig_len]; + signature sig; // test salt - std::pair test_salt("foobar", 6); + span test_salt("foobar", 6); // test vector 2 (the keypair is the same as test 1) - sign_mutable_item(test_content, test_salt, 1, public_key - , private_key, signature); + sign_mutable_item(test_content, test_salt, sequence_number(1), pk, sk, sig); - TEST_EQUAL(aux::to_hex(std::string(signature, 64)) + TEST_EQUAL(aux::to_hex(std::string(sig.bytes.data(), signature::len)) , "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d" "df9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"); - sha1_hash target_id = item_target_id(test_salt, public_key); + sha1_hash target_id = item_target_id(test_salt, pk); TEST_EQUAL(aux::to_hex(target_id.to_string()), "411eba73b6f087ca51a3795d9c8c938d365e32c1"); } @@ -2418,7 +2431,7 @@ TORRENT_TEST(signing_test3) // test vector 3 // test content - std::pair test_content("12:Hello World!", 15); + span test_content("12:Hello World!", 15); sha1_hash target_id = item_target_id(test_content); TEST_EQUAL(aux::to_hex(target_id.to_string()), "e5f96f6f38320f0f33959cb4d3d656452117aadb"); @@ -2704,7 +2717,7 @@ TORRENT_TEST(read_only_node) send_dht_request(node, "ping", source, &response, args, "10", false); TEST_EQUAL(response.type(), bdecode_node::none_t); - args.target("01010101010101010101"); + args.target(sha1_hash("01010101010101010101")); send_dht_request(node, "get", source, &response, args, "10", false); TEST_EQUAL(response.type(), bdecode_node::none_t); diff --git a/test/test_dht_storage.cpp b/test/test_dht_storage.cpp index 1238d4efc..8b29beb84 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/session.hpp" -#include "libtorrent/kademlia/node.hpp" // for verify_message +#include "libtorrent/kademlia/msg.hpp" // for verify_message #include "libtorrent/bencode.hpp" #include "libtorrent/socket_io.hpp" // for hash_address #include "libtorrent/broadcast_socket.hpp" // for supports_ipv6 @@ -138,23 +138,24 @@ TORRENT_TEST(put_immutable_item) bool r = s->get_immutable_item(n4, item); TEST_CHECK(!r); - s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n4, {"123", 3}, addr("124.31.75.21")); r = s->get_immutable_item(n4, item); TEST_CHECK(r); - s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n1, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21")); r = s->get_immutable_item(n1, item); TEST_CHECK(!r); - r = s->get_mutable_item(n4, 0, false, item); + r = s->get_mutable_item(n4, sequence_number(0), false, item); TEST_CHECK(!r); - char public_key[item_pk_len]; - char signature[item_sig_len]; - s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); - r = s->get_mutable_item(n4, 0, false, item); + public_key pk; + signature sig; + s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk + , {"salt", 4}, addr("124.31.75.21")); + r = s->get_mutable_item(n4, sequence_number(0), false, item); TEST_CHECK(r); } @@ -188,17 +189,18 @@ TORRENT_TEST(counters) entry item; - s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n4, {"123", 3}, addr("124.31.75.21")); TEST_EQUAL(s->counters().immutable_data, 1); - s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); - s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n1, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21")); + s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21")); TEST_EQUAL(s->counters().immutable_data, 2); - char public_key[item_pk_len]; - char signature[item_sig_len]; - s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); + public_key pk; + signature sig; + s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk + , {"salt", 4}, addr("124.31.75.21")); TEST_EQUAL(s->counters().mutable_data, 1); } @@ -286,7 +288,7 @@ TORRENT_TEST(immutable_item_limit) for (int i = 0; i < 200; ++i) { - s->put_immutable_item(rand_hash(), "123", 3, rand_v4()); + s->put_immutable_item(rand_hash(), {"123", 3}, rand_v4()); dht_storage_counters cnt = s->counters(); TEST_CHECK(cnt.immutable_data <= 42); } @@ -300,11 +302,12 @@ TORRENT_TEST(mutable_item_limit) sett.max_dht_items = 42; std::unique_ptr s(create_default_dht_storage(sett)); - char public_key[item_pk_len]; - char signature[item_sig_len]; + public_key pk; + signature sig; for (int i = 0; i < 200; ++i) { - s->put_mutable_item(rand_hash(), "123", 3, signature, 1, public_key, "salt", 4, rand_v4()); + s->put_mutable_item(rand_hash(), {"123", 3}, sig, sequence_number(1) + , pk, {"salt", 4}, rand_v4()); dht_storage_counters cnt = s->counters(); TEST_CHECK(cnt.mutable_data <= 42); } @@ -342,15 +345,15 @@ TORRENT_TEST(update_node_ids) // all items will have one announcer, all calculations // for item erase will be reduced to the distance - s->put_immutable_item(h1, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(h1, {"123", 3}, addr("124.31.75.21")); cnt = s->counters(); TEST_EQUAL(cnt.immutable_data, 1); - s->put_immutable_item(h2, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(h2, {"123", 3}, addr("124.31.75.21")); cnt = s->counters(); TEST_EQUAL(cnt.immutable_data, 2); // at this point, the least important (h2) will removed // to make room for h3 - s->put_immutable_item(h3, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(h3, {"123", 3}, addr("124.31.75.21")); cnt = s->counters(); TEST_EQUAL(cnt.immutable_data, 2); diff --git a/test/test_direct_dht.cpp b/test/test_direct_dht.cpp index c89cd505e..c8b927fdc 100644 --- a/test/test_direct_dht.cpp +++ b/test/test_direct_dht.cpp @@ -69,8 +69,8 @@ dht_direct_response_alert* get_direct_response(lt::session& ses) { for (;;) { - alert* a = ses.wait_for_alert(seconds(20)); - // it shouldn't take more than 20 seconds to get a response + alert* a = ses.wait_for_alert(seconds(30)); + // it shouldn't take more than 30 seconds to get a response // so fail the test and bail out if we don't get an alert in that time TEST_CHECK(a); if (!a) return nullptr; diff --git a/tools/dht_put.cpp b/tools/dht_put.cpp index 1b0a01204..4db732f5f 100644 --- a/tools/dht_put.cpp +++ b/tools/dht_put.cpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" // for bencode() #include "libtorrent/kademlia/item.hpp" // for sign_mutable_item #include "libtorrent/ed25519.hpp" +#include "libtorrent/span.hpp" #include #include // for snprintf @@ -112,8 +113,11 @@ alert* wait_for_alert(lt::session& s, int alert_type) return ret; } -void put_string(entry& e, std::array& sig, std::uint64_t& seq - , std::string const& salt, char const* public_key, char const* private_key +void put_string(entry& e, std::array& sig + , std::uint64_t& seq + , std::string const& salt + , std::array const& pk + , std::array const& sk , char const* str) { using libtorrent::dht::sign_mutable_item; @@ -121,13 +125,12 @@ void put_string(entry& e, std::array& sig, std::uint64_t& seq e = std::string(str); std::vector buf; bencode(std::back_inserter(buf), e); + dht::signature sign; ++seq; - sign_mutable_item(std::pair(&buf[0], int(buf.size())) - , std::pair(&salt[0], int(salt.size())) - , seq - , public_key - , private_key - , sig.data()); + sign_mutable_item(buf, salt, dht::sequence_number(seq) + , dht::public_key(pk.data()) + , dht::secret_key(sk.data()), sign); + sig = sign.bytes; } void bootstrap(lt::session& s) @@ -156,14 +159,14 @@ int dump_key(char *filename) } std::fclose(f); - std::array public_key; - std::array private_key; - ed25519_create_keypair((unsigned char*)public_key.data() - , (unsigned char*)private_key.data(), seed); + std::array pk; + std::array sk; + ed25519_create_keypair((unsigned char*)pk.data() + , (unsigned char*)sk.data(), seed); - std::printf("public key: %s\nprivate key: %s\n", - to_hex(std::string(public_key.data(), public_key.size())).c_str(), - to_hex(std::string(private_key.data(), private_key.size())).c_str()); + std::printf("public key: %s\nprivate key: %s\n" + , to_hex(std::string(pk.data(), pk.size())).c_str() + , to_hex(std::string(sk.data(), sk.size())).c_str()); return 0; } @@ -359,7 +362,7 @@ int main(int argc, char* argv[]) bootstrap(s); s.dht_put_item(public_key, std::bind(&put_string, _1, _2, _3, _4 - , public_key.data(), private_key.data(), argv[0])); + , public_key, private_key, argv[0])); std::printf("MPUT publick key: %s\n", to_hex(std::string(public_key.data() , public_key.size())).c_str());