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.
This commit is contained in:
Arvid Norberg 2016-07-23 15:57:04 -07:00 committed by GitHub
parent ddb274751f
commit 9c2325ff6b
41 changed files with 781 additions and 682 deletions

View File

@ -297,6 +297,8 @@ rule warnings ( properties * )
result += <cflags>/wd4251 ; result += <cflags>/wd4251 ;
# disable warning C4275: non DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier' # disable warning C4275: non DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier'
result += <cflags>/wd4275 ; result += <cflags>/wd4275 ;
# disable warning C4373: virtual function overrides, previous versions of the compiler did not override when parameters only differed by const/volatile qualifiers
result += <cflags>/wd4373 ;
} }
return $(result) ; return $(result) ;

View File

@ -457,9 +457,9 @@ namespace
ses.dht_get_item(public_key, salt); ses.dht_get_item(public_key, salt);
} }
void put_string(entry& e, std::array<char, 64>& sig, std::uint64_t& seq, void put_string(entry& e, std::array<char, 64>& sig, std::uint64_t& seq
std::string const& salt, std::string public_key, std::string private_key, , std::string const& salt, std::string pk, std::string sk
std::string data) , std::string data)
{ {
using libtorrent::dht::sign_mutable_item; using libtorrent::dht::sign_mutable_item;
@ -467,9 +467,13 @@ namespace
std::vector<char> buf; std::vector<char> buf;
bencode(std::back_inserter(buf), e); bencode(std::back_inserter(buf), e);
++seq; ++seq;
sign_mutable_item(std::pair<char const*, int>(&buf[0], int(buf.size())) dht::signature sign;
, std::pair<char const*, int>(&salt[0], int(salt.size())) sign_mutable_item(buf, salt
, seq, public_key.c_str(), private_key.c_str(), sig.data()); , 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, void dht_put_mutable_item(lt::session& ses, std::string private_key, std::string public_key,

View File

@ -194,6 +194,7 @@ nobase_include_HEADERS = \
kademlia/routing_table.hpp \ kademlia/routing_table.hpp \
kademlia/rpc_manager.hpp \ kademlia/rpc_manager.hpp \
kademlia/traversal_algorithm.hpp \ kademlia/traversal_algorithm.hpp \
kademlia/types.hpp \
kademlia/item.hpp \ kademlia/item.hpp \
kademlia/get_item.hpp \ kademlia/get_item.hpp \
kademlia/get_peers.hpp kademlia/get_peers.hpp

View File

@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/disable_warnings_pop.hpp" #include "libtorrent/aux_/disable_warnings_pop.hpp"
#include "libtorrent/assert.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. // There are 5 different types of nodes, see type_t.
struct TORRENT_EXPORT bdecode_node struct TORRENT_EXPORT bdecode_node
{ {
// TODO: 3 make this take span<char const> for buffer, and make it return a
// bdecode_node
TORRENT_EXPORT friend int bdecode(char const* start, char const* end, bdecode_node& ret TORRENT_EXPORT friend int bdecode(char const* start, char const* end, bdecode_node& ret
, error_code& ec, int* error_pos, int depth_limit , error_code& ec, int* error_pos, int depth_limit
, int token_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 // 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 // starts with ``d`` and ends with ``e``, and has all the content of the
// dictionary in between. // dictionary in between.
std::pair<char const*, int> data_section() const; span<char const> data_section() const;
// functions with the ``list_`` prefix operate on lists. These functions are // functions with the ``list_`` prefix operate on lists. These functions are
// only valid if ``type()`` == ``list_t``. ``list_at()`` returns the item // only valid if ``type()`` == ``list_t``. ``list_at()`` returns the item

View File

@ -20,6 +20,8 @@ extern "C" {
void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed); void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed);
#endif #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_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); 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); int TORRENT_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);

View File

@ -49,6 +49,7 @@ namespace libtorrent
namespace aux { namespace aux {
TORRENT_EXTRA_EXPORT int hex_to_int(char in); 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); TORRENT_EXTRA_EXPORT bool is_hex(char const *in, int len);
// The overload taking a ``std::string`` converts (binary) the string ``s`` // 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 // ``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. // 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); 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); TORRENT_DEPRECATED_EXPORT void to_hex(char const *in, int len, char* out);
// converts the buffer [``in``, ``in`` + len) from hexadecimal to // 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 // 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. // at ``out`` has enough space for the result to be written to, i.e.
// (len + 1) / 2 bytes. // (len + 1) / 2 bytes.
// TODO: 3 take an span here instead
TORRENT_DEPRECATED_EXPORT bool from_hex(char const *in, int len, char* out); TORRENT_DEPRECATED_EXPORT bool from_hex(char const *in, int len, char* out);
} }

View File

@ -40,10 +40,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/disable_warnings_pop.hpp" #include "libtorrent/aux_/disable_warnings_pop.hpp"
#include <libtorrent/kademlia/node_id.hpp> #include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/types.hpp>
#include <libtorrent/socket.hpp> #include <libtorrent/socket.hpp>
#include <libtorrent/sha1_hash.hpp> #include <libtorrent/sha1_hash.hpp>
#include <libtorrent/address.hpp> #include <libtorrent/address.hpp>
#include <libtorrent/span.hpp>
namespace libtorrent namespace libtorrent
{ {
@ -164,7 +166,7 @@ namespace dht
// dht_settings::max_dht_items. // dht_settings::max_dht_items.
// //
virtual void put_immutable_item(sha1_hash const& target virtual void put_immutable_item(sha1_hash const& target
, char const* buf, int size , span<char const> buf
, address const& addr) = 0; , address const& addr) = 0;
// This function retrieves the sequence number of a mutable item. // This function retrieves the sequence number of a mutable item.
@ -173,7 +175,7 @@ namespace dht
// inside the out parameter seq. // inside the out parameter seq.
// //
virtual bool get_mutable_item_seq(sha1_hash const& target 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. // This function retrieves the mutable stored in the DHT.
// //
@ -189,7 +191,7 @@ namespace dht
// inside the (entry) out parameter item. // inside the (entry) out parameter item.
// //
virtual bool get_mutable_item(sha1_hash const& target 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; , entry& item) const = 0;
// Store the item's data. This layer is only for storage. // Store the item's data. This layer is only for storage.
@ -201,11 +203,11 @@ namespace dht
// dht_settings::max_dht_items. // dht_settings::max_dht_items.
// //
virtual void put_mutable_item(sha1_hash const& target virtual void put_mutable_item(sha1_hash const& target
, char const* buf, int size , span<char const> buf
, char const* sig , signature const& sig
, std::int64_t seq , sequence_number seq
, char const* pk , public_key const& pk
, char const* salt, int salt_size , span<char const> salt
, address const& addr) = 0; , address const& addr) = 0;
// This function is called periodically (non-constant frequency). // This function is called periodically (non-constant frequency).

View File

@ -106,7 +106,7 @@ namespace libtorrent { namespace dht
// key is a 32-byte binary string, the public key to look up. // key is a 32-byte binary string, the public key to look up.
// the salt is optional // the salt is optional
void get_item(char const* key void get_item(public_key const& key
, boost::function<void(item const&, bool)> cb , boost::function<void(item const&, bool)> cb
, std::string salt = std::string()); , std::string salt = std::string());
@ -119,7 +119,7 @@ namespace libtorrent { namespace dht
// for mutable_item. // for mutable_item.
// the data_cb will be called when we get authoritative mutable_item, // the data_cb will be called when we get authoritative mutable_item,
// the cb is same as put immutable_item. // the cb is same as put immutable_item.
void put_item(char const* key void put_item(public_key const& key
, boost::function<void(item const&, int)> cb , boost::function<void(item const&, int)> cb
, boost::function<void(item&)> data_cb, std::string salt = std::string()); , boost::function<void(item&)> data_cb, std::string salt = std::string());

View File

@ -65,7 +65,7 @@ struct find_data : traversal_algorithm
{ {
typedef boost::function<void(std::vector<std::pair<node_entry, std::string> > const&)> nodes_callback; typedef boost::function<void(std::vector<std::pair<node_entry, std::string> > const&)> nodes_callback;
find_data(node & node, node_id target find_data(node& node, node_id target
, nodes_callback const& ncallback); , nodes_callback const& ncallback);
void got_write_token(node_id const& n, std::string const& write_token); void got_write_token(node_id const& n, std::string const& write_token);

View File

@ -46,9 +46,9 @@ public:
typedef boost::function<void(item const&, bool)> data_callback; typedef boost::function<void(item const&, bool)> data_callback;
void got_data(bdecode_node const& v, void got_data(bdecode_node const& v,
char const* pk, public_key const& pk,
std::uint64_t seq, sequence_number seq,
char const* sig); signature const& sig);
// for immutable itms // for immutable itms
get_item(node& dht_node get_item(node& dht_node
@ -58,8 +58,8 @@ public:
// for mutable items // for mutable items
get_item(node& dht_node get_item(node& dht_node
, char const* pk , public_key const& pk
, std::string const& salt , span<char const> salt
, data_callback const& dcallback , data_callback const& dcallback
, nodes_callback const& ncallback); , nodes_callback const& ncallback);

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2013, Steven Siloti Copyright (c) 2013, Steven Siloti, Arvid Norberg
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -36,6 +36,9 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/sha1_hash.hpp> #include <libtorrent/sha1_hash.hpp>
#include <libtorrent/bdecode.hpp> #include <libtorrent/bdecode.hpp>
#include <libtorrent/entry.hpp> #include <libtorrent/entry.hpp>
#include <libtorrent/span.hpp>
#include <libtorrent/kademlia/types.hpp>
#include <vector> #include <vector>
#include <exception> #include <exception>
#include <array> #include <array>
@ -44,19 +47,18 @@ namespace libtorrent { namespace dht
{ {
// calculate the target hash for an immutable item. // calculate the target hash for an immutable item.
sha1_hash TORRENT_EXTRA_EXPORT item_target_id( sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span<char const> v);
std::pair<char const*, int> v);
// calculate the target hash for a mutable item. // calculate the target hash for a mutable item.
sha1_hash TORRENT_EXTRA_EXPORT item_target_id(std::pair<char const*, int> salt sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span<char const> salt
, char const* pk); , public_key const& pk);
bool TORRENT_EXTRA_EXPORT verify_mutable_item( bool TORRENT_EXTRA_EXPORT verify_mutable_item(
std::pair<char const*, int> v span<char const> v
, std::pair<char const*, int> salt , span<char const> salt
, std::uint64_t seq , sequence_number seq
, char const* pk , public_key const& pk
, char const* sig); , signature const& sig);
// TODO: since this is a public function, it should probably be moved // TODO: since this is a public function, it should probably be moved
// out of this header and into one with other public functions. // 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 // is responsible for allocating the destination buffer that's passed in
// as the ``sig`` argument. Typically it would be allocated on the stack. // as the ``sig`` argument. Typically it would be allocated on the stack.
void TORRENT_EXPORT sign_mutable_item( void TORRENT_EXPORT sign_mutable_item(
std::pair<char const*, int> v span<char const> v
, std::pair<char const*, int> salt , span<char const> salt
, std::uint64_t seq , sequence_number seq
, char const* pk , public_key const& pk
, char const* sk , secret_key const& sk
, char* sig); , signature& sig);
enum
{
item_pk_len = 32,
item_sk_len = 64,
item_sig_len = 64
};
class TORRENT_EXTRA_EXPORT item class TORRENT_EXTRA_EXPORT item
{ {
public: public:
item() : m_seq(0), m_mutable(false) {} item() : m_seq(0), m_mutable(false) {}
item(char const* pk, std::string const& salt); item(public_key const& pk, span<char const> salt);
item(entry const& v) { assign(v); } item(entry v);
item(entry const& v item(entry v
, std::pair<char const*, int> salt , span<char const> salt
, std::uint64_t seq, char const* pk, char const* sk); , sequence_number seq
item(bdecode_node const& v) { assign(v); } , public_key const& pk
, secret_key const& sk);
item(bdecode_node const& v);
void assign(entry const& v) void assign(entry v);
{ void assign(entry v, span<char const> salt
assign(v, std::pair<char const*, int>(static_cast<char const*>(nullptr) , sequence_number seq
, 0), 0, nullptr, nullptr); , public_key const& pk
} , secret_key const& sk);
void assign(entry const& v, std::pair<char const*, int> salt void assign(bdecode_node const& v);
, std::uint64_t seq, char const* pk, char const* sk); bool assign(bdecode_node const& v, span<char const> salt
void assign(bdecode_node const& v) , sequence_number seq
{ , public_key const& pk
assign(v, std::pair<char const*, int>(static_cast<char const*>(nullptr) , signature const& sig);
, 0), 0, nullptr, nullptr); void assign(entry v, span<char const> salt
} , sequence_number seq
bool assign(bdecode_node const& v, std::pair<char const*, int> salt , public_key const& pk
, std::uint64_t seq, char const* pk, char const* sig); , signature const& sig);
void assign(entry const& v, std::string salt, std::uint64_t seq
, char const* pk, char const* sig);
void clear() { m_value = entry(); } void clear() { m_value = entry(); }
bool empty() const { return m_value.type() == entry::undefined_t; } bool empty() const { return m_value.type() == entry::undefined_t; }
@ -116,19 +111,19 @@ public:
bool is_mutable() const { return m_mutable; } bool is_mutable() const { return m_mutable; }
entry const& value() const { return m_value; } entry const& value() const { return m_value; }
std::array<char, item_pk_len> const& pk() const public_key const& pk() const
{ return m_pk; } { return m_pk; }
std::array<char, item_sig_len> const& sig() const signature const& sig() const
{ return m_sig; } { 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; } std::string const& salt() const { return m_salt; }
private: private:
entry m_value; entry m_value;
std::string m_salt; std::string m_salt;
std::array<char, item_pk_len> m_pk; public_key m_pk;
std::array<char, item_sig_len> m_sig; signature m_sig;
std::uint64_t m_seq; sequence_number m_seq;
bool m_mutable; bool m_mutable;
}; };

View File

@ -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 // given a redundant name to avoid clashing with libtorrent::detail
namespace dht_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[] TORRENT_EXPORT bool verify_message(bdecode_node const& msg, key_desc_t const desc[]
, bdecode_node ret[], int size, char* error, int error_size); , bdecode_node ret[], int size, char* error, int error_size);

View File

@ -150,17 +150,17 @@ public:
, boost::function<void(msg const&)> f); , boost::function<void(msg const&)> f);
void get_item(sha1_hash const& target, boost::function<void(item const&)> f); void get_item(sha1_hash const& target, boost::function<void(item const&)> f);
void get_item(char const* pk, std::string const& salt, boost::function<void(item const&, bool)> f); void get_item(public_key const& pk, std::string const& salt, boost::function<void(item const&, bool)> f);
void put_item(sha1_hash const& target, entry const& data, boost::function<void(int)> f); void put_item(sha1_hash const& target, entry const& data, boost::function<void(int)> f);
void put_item(char const* pk, std::string const& salt void put_item(public_key const& pk, std::string const& salt
, boost::function<void(item const&, int)> f , boost::function<void(item const&, int)> f
, boost::function<void(item&)> data_cb); , boost::function<void(item&)> 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; , 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() // the returned time is the delay until connection_timeout()
// should be called again the next time // should be called again the next time

View File

@ -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 <cstdint>
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<char, len> 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<char, len> 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<char, len> 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

View File

@ -84,6 +84,7 @@ namespace libtorrent { namespace aux
return ret; return ret;
} }
// TODO: 3 use span<> here
int copy_buffer(char const* buf, int const size) int copy_buffer(char const* buf, int const size)
{ {
int const ret = int(m_storage.size()); int const ret = int(m_storage.size());

View File

@ -284,8 +284,8 @@ TORRENT_TEST(dht_dual_stack_mutable_item)
dht_network dht(sim, 100); dht_network dht(sim, 100);
dht_network dht6(sim, 100, dht_network::bind_ipv6); dht_network dht6(sim, 100, dht_network::bind_ipv6);
std::array<char, ed25519_private_key_size> sk; lt::dht::secret_key sk;
std::array<char, ed25519_public_key_size> pk; lt::dht::public_key pk;
int put_count = 0; int put_count = 0;
bool got_item = false; bool got_item = false;
@ -302,7 +302,7 @@ TORRENT_TEST(dht_dual_stack_mutable_item)
{ {
TEST_CHECK(!got_item); TEST_CHECK(!got_item);
if (p->authoritative) 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? // terminate?
@ -315,28 +315,28 @@ TORRENT_TEST(dht_dual_stack_mutable_item)
if (ticks == 2) if (ticks == 2)
{ {
std::array<unsigned char, ed25519_seed_size> seed; std::array<unsigned char, ed25519_seed_size> seed;
ed25519_create_keypair((unsigned char*)pk.data() ed25519_create_keypair((unsigned char*)pk.bytes.data()
, (unsigned char*)sk.data(), seed.data()); , (unsigned char*)sk.bytes.data(), seed.data());
ses.dht_put_item(pk, [&](lt::entry& item, std::array<char, 64>& sig ses.dht_put_item(pk.bytes, [&](lt::entry& item, std::array<char, 64>& sig
, std::uint64_t& seq, std::string const& salt) , std::uint64_t& seq, std::string const& salt)
{ {
item = "mutable item"; item = "mutable item";
seq = 1; seq = 1;
std::vector<char> v; std::vector<char> v;
lt::dht::signature sign;
lt::bencode(std::back_inserter(v), item); lt::bencode(std::back_inserter(v), item);
lt::dht::sign_mutable_item( lt::dht::sign_mutable_item(v, salt
std::make_pair(v.data(), int(v.size())) , lt::dht::sequence_number(seq), pk, sk, sign);
, std::make_pair(salt.data(), int(salt.size()))
, seq, pk.data(), sk.data(), sig.data());
put_count++; put_count++;
sig = sign.bytes;
}); });
} }
if (ticks == 4) if (ticks == 4)
{ {
// should be one for each stack, ipv4 and ipv6 // should be one for each stack, ipv4 and ipv6
TEST_EQUAL(put_count, 2); TEST_EQUAL(put_count, 2);
ses.dht_get_item(pk); ses.dht_get_item(pk.bytes);
} }
if (ticks == 6) if (ticks == 6)
{ {

View File

@ -107,7 +107,7 @@ void test_expiration(high_resolution_clock::duration const& expiry_time
{ {
default_config cfg; default_config cfg;
simulation sim(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); sim::asio::high_resolution_timer timer(ios);
timer.expires_from_now(expiry_time); 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(n2, p3, "torrent_name1", false);
s->announce_peer(n3, p4, "torrent_name2", 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")); dht::public_key pk;
s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); dht::signature sig;
s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk, {"salt", 4}
, addr("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_storage_counters c; dht_storage_counters c;
// note that we are using the aux global timer // note that we are using the aux global timer

View File

@ -1886,6 +1886,7 @@ namespace libtorrent {
return ret; return ret;
} }
// TODO: 3 use span<> here
dht_pkt_alert::dht_pkt_alert(aux::stack_allocator& alloc dht_pkt_alert::dht_pkt_alert(aux::stack_allocator& alloc
, char const* buf, int size, dht_pkt_alert::direction_t d, udp::endpoint ep) , char const* buf, int size, dht_pkt_alert::direction_t d, udp::endpoint ep)
: dir(d) : dir(d)
@ -1987,8 +1988,9 @@ namespace libtorrent {
aux::stack_allocator& alloc, void* userdata_ aux::stack_allocator& alloc, void* userdata_
, udp::endpoint const& addr_, bdecode_node const& response) , udp::endpoint const& addr_, bdecode_node const& response)
: userdata(userdata_), addr(addr_), m_alloc(alloc) : userdata(userdata_), addr(addr_), m_alloc(alloc)
, m_response_idx(alloc.copy_buffer(response.data_section().first, response.data_section().second)) , m_response_idx(alloc.copy_buffer(response.data_section().data()
, m_response_size(response.data_section().second) , int(response.data_section().size())))
, m_response_size(int(response.data_section().size()))
{} {}
dht_direct_response_alert::dht_direct_response_alert( dht_direct_response_alert::dht_direct_response_alert(

View File

@ -303,14 +303,14 @@ namespace libtorrent
bdecode_node::operator bool() const bdecode_node::operator bool() const
{ return m_token_idx != -1; } { return m_token_idx != -1; }
std::pair<char const*, int> bdecode_node::data_section() const span<char const> bdecode_node::data_section() const
{ {
if (m_token_idx == -1) return std::make_pair(m_buffer, 0); if (m_token_idx == -1) return span<char const>();
TORRENT_ASSERT(m_token_idx != -1); TORRENT_ASSERT(m_token_idx != -1);
bdecode_token const& t = m_root_tokens[m_token_idx]; bdecode_token const& t = m_root_tokens[m_token_idx];
bdecode_token const& next = m_root_tokens[m_token_idx + t.next_item]; 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 bdecode_node bdecode_node::list_at(int i) const

View File

@ -95,8 +95,8 @@ namespace libtorrent
, sha1_hash const& stream_key, bool const outgoing) , sha1_hash const& stream_key, bool const outgoing)
{ {
hasher h; hasher h;
static const char keyA[] = "keyA"; static const char keyA[] = {'k', 'e', 'y', 'A'};
static const char keyB[] = "keyB"; static const char keyB[] = {'k', 'e', 'y', 'B'};
// encryption rc4 longkeys // encryption rc4 longkeys
// outgoing connection : hash ('keyA',S,SKEY) // outgoing connection : hash ('keyA',S,SKEY)
@ -105,10 +105,10 @@ namespace libtorrent
std::array<char, 96> secret_buf; std::array<char, 96> secret_buf;
mp::export_bits(secret, reinterpret_cast<std::uint8_t*>(secret_buf.data()), 8); mp::export_bits(secret, reinterpret_cast<std::uint8_t*>(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(secret_buf);
h.update(stream_key); h.update(stream_key);
const sha1_hash local_key = h.final(); sha1_hash const local_key = h.final();
h.reset(); h.reset();
@ -116,10 +116,10 @@ namespace libtorrent
// outgoing connection : hash ('keyB',S,SKEY) // outgoing connection : hash ('keyB',S,SKEY)
// incoming connection : hash ('keyA',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(secret_buf);
h.update(stream_key); h.update(stream_key);
const sha1_hash remote_key = h.final(); sha1_hash const remote_key = h.final();
boost::shared_ptr<rc4_handler> ret = boost::make_shared<rc4_handler>(); boost::shared_ptr<rc4_handler> ret = boost::make_shared<rc4_handler>();
@ -557,27 +557,30 @@ namespace libtorrent
char msg[20 + 20 + 8 + 4 + 2 + 512 + 2]; char msg[20 + 20 + 8 + 4 + 2 + 512 + 2];
char* ptr = msg; char* ptr = msg;
static char const req1[4] = {'r', 'e', 'q', '1'};
// sync hash (hash('req1',S)) // sync hash (hash('req1',S))
h.reset(); h.reset();
h.update("req1",4); h.update(req1);
h.update(secret); h.update(secret);
sha1_hash const sync_hash = h.final(); sha1_hash const sync_hash = h.final();
memcpy(ptr, sync_hash.data(), 20); std::memcpy(ptr, sync_hash.data(), 20);
ptr += 20; ptr += 20;
static char const req2[4] = {'r', 'e', 'q', '2'};
// stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ] // stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ]
h.reset(); h.reset();
h.update("req2",4); h.update(req2);
h.update(info_hash); h.update(info_hash);
sha1_hash const streamkey_hash = h.final(); sha1_hash const streamkey_hash = h.final();
static char const req3[4] = {'r', 'e', 'q', '3'};
h.reset(); h.reset();
h.update("req3",4); h.update(req3);
h.update(secret); h.update(secret);
sha1_hash const obfsc_hash = h.final() ^ streamkey_hash; sha1_hash const obfsc_hash = h.final() ^ streamkey_hash;
memcpy(ptr, obfsc_hash.data(), 20); std::memcpy(ptr, obfsc_hash.data(), 20);
ptr += 20; ptr += 20;
// Discard DH key exchange data, setup RC4 keys // 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 // if we're encrypting this buffer, we need to make a copy
// since we'll mutate it // since we'll mutate it
char* buf = static_cast<char*>(malloc(size)); char* buf = static_cast<char*>(malloc(size));
memcpy(buf, buffer, size); std::memcpy(buf, buffer, size);
append_send_buffer(buf, size, &regular_c_free, nullptr); append_send_buffer(buf, size, &regular_c_free, nullptr);
destructor(const_cast<char*>(buffer), userdata, ref); destructor(const_cast<char*>(buffer), userdata, ref);
} }
@ -757,7 +760,7 @@ namespace libtorrent
// length of version string // length of version string
detail::write_uint8(string_len, ptr); detail::write_uint8(string_len, ptr);
// protocol identifier // protocol identifier
memcpy(ptr, version_string, string_len); std::memcpy(ptr, version_string, string_len);
ptr += string_len; ptr += string_len;
// 8 zeroes // 8 zeroes
memset(ptr, 0, 8); memset(ptr, 0, 8);
@ -798,7 +801,7 @@ namespace libtorrent
// info hash // info hash
sha1_hash const& ih = t->torrent_file().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; ptr += 20;
// peer id // peer id
@ -810,7 +813,7 @@ namespace libtorrent
m_our_peer_id[i] = random() & 0xff; 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; ptr += 20;
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
@ -2632,15 +2635,14 @@ namespace libtorrent
if (!m_sync_hash.get()) if (!m_sync_hash.get())
{ {
TORRENT_ASSERT(m_sync_bytes_read == 0); TORRENT_ASSERT(m_sync_bytes_read == 0);
hasher h;
static char const req1[4] = {'r', 'e', 'q', '1'};
// compute synchash (hash('req1',S)) // compute synchash (hash('req1',S))
std::array<char, 96> buffer; std::array<char, 96> buffer;
mp::export_bits(m_dh_key_exchange->get_secret() mp::export_bits(m_dh_key_exchange->get_secret()
, reinterpret_cast<std::uint8_t*>(buffer.data()), 8); , reinterpret_cast<std::uint8_t*>(buffer.data()), 8);
h.update("req1", 4); hasher h(req1);
h.update(buffer); h.update(buffer);
m_sync_hash.reset(new sha1_hash(h.final())); m_sync_hash.reset(new sha1_hash(h.final()));
} }

View File

@ -570,7 +570,7 @@ namespace libtorrent
std::string split = split_path(m_files.symlink(0)); std::string split = split_path(m_files.symlink(0));
for (char const* e = split.c_str(); e != nullptr; e = next_path_element(e)) 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()) if (!m_filehashes.empty())
{ {

View File

@ -85,27 +85,13 @@ namespace
std::set<peer_entry> peers; std::set<peer_entry> peers;
}; };
#ifndef TORRENT_NO_DEPRECATE
struct count_peers
{
int* count;
explicit count_peers(int* c): count(c) {}
void operator()(std::pair<libtorrent::sha1_hash
, torrent_entry> const& t)
{
*count += int(t.second.peers.size());
}
};
#endif
// TODO: 2 make this configurable in dht_settings // TODO: 2 make this configurable in dht_settings
enum { announce_interval = 30 }; enum { announce_interval = 30 };
struct dht_immutable_item struct dht_immutable_item
{ {
dht_immutable_item() : value(nullptr), num_announcers(0), size(0) {} // the actual value
// malloced space for the actual value std::unique_ptr<char[]> value;
char* value;
// this counts the number of IPs we have seen // this counts the number of IPs we have seen
// announcing this item, this is used to determine // announcing this item, this is used to determine
// popularity if we reach the limit of items to store // popularity if we reach the limit of items to store
@ -113,20 +99,17 @@ namespace
// the last time we heard about this // the last time we heard about this
time_point last_seen; time_point last_seen;
// number of IPs in the bloom filter // number of IPs in the bloom filter
int num_announcers; int num_announcers = 0;
// size of malloced space pointed to by value // 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 struct dht_mutable_item : dht_immutable_item
{ {
char sig[item_sig_len]; signature sig;
std::int64_t seq; sequence_number seq;
ed25519_public_key key; public_key key;
char* salt; std::string salt;
int salt_size;
}; };
void touch_item(dht_immutable_item* f, address const& address) void touch_item(dht_immutable_item* f, address const& address)
@ -150,11 +133,12 @@ namespace
explicit immutable_item_comparator(std::vector<node_id> const& node_ids) : m_node_ids(node_ids) {} explicit immutable_item_comparator(std::vector<node_id> const& node_ids) : m_node_ids(node_ids) {}
immutable_item_comparator(immutable_item_comparator const&) = default; immutable_item_comparator(immutable_item_comparator const&) = default;
bool operator() (std::pair<node_id, dht_immutable_item> const& lhs template <typename Item>
, std::pair<node_id, dht_immutable_item> const& rhs) const bool operator()(std::pair<node_id const, Item> const& lhs
, std::pair<node_id const, Item> const& rhs) const
{ {
int l_distance = min_distance_exp(lhs.first, m_node_ids); int const l_distance = min_distance_exp(lhs.first, m_node_ids);
int r_distance = min_distance_exp(rhs.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 // this is a score taking the popularity (number of announcers) and the
// fit, in terms of distance from ideal storing node, into account. // fit, in terms of distance from ideal storing node, into account.
@ -180,16 +164,15 @@ namespace
typename std::map<node_id, Item>::const_iterator pick_least_important_item( typename std::map<node_id, Item>::const_iterator pick_least_important_item(
std::vector<node_id> const& node_ids, std::map<node_id, Item> const& table) std::vector<node_id> const& node_ids, std::map<node_id, Item> const& table)
{ {
return std::min_element(table.begin() return std::min_element(table.begin(), table.end()
, table.end()
, immutable_item_comparator(node_ids)); , immutable_item_comparator(node_ids));
} }
class dht_default_storage final : public dht_storage_interface, boost::noncopyable class dht_default_storage final : public dht_storage_interface, boost::noncopyable
{ {
typedef std::map<node_id, torrent_entry> table_t; using table_t = std::map<node_id, torrent_entry>;
typedef std::map<node_id, dht_immutable_item> dht_immutable_table_t; using dht_immutable_table_t = std::map<node_id, dht_immutable_item>;
typedef std::map<node_id, dht_mutable_item> dht_mutable_table_t; using dht_mutable_table_t = std::map<node_id, dht_mutable_item>;
public: public:
@ -205,8 +188,9 @@ namespace
size_t num_torrents() const override { return m_map.size(); } size_t num_torrents() const override { return m_map.size(); }
size_t num_peers() const override size_t num_peers() const override
{ {
int ret = 0; size_t ret = 0;
std::for_each(m_map.begin(), m_map.end(), count_peers(&ret)); for (auto const& t : m_map)
ret += t.second.peers.size();
return ret; return ret;
} }
#endif #endif
@ -216,7 +200,7 @@ namespace
} }
bool get_peers(sha1_hash const& info_hash bool get_peers(sha1_hash const& info_hash
, bool noseed, bool scrape , bool const noseed, bool const scrape
, entry& peers) const override , entry& peers) const override
{ {
table_t::const_iterator i = m_map.lower_bound(info_hash); table_t::const_iterator i = m_map.lower_bound(info_hash);
@ -275,7 +259,7 @@ namespace
void announce_peer(sha1_hash const& info_hash void announce_peer(sha1_hash const& info_hash
, tcp::endpoint const& endp , 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); table_t::iterator ti = m_map.find(info_hash);
torrent_entry* v; torrent_entry* v;
@ -348,12 +332,13 @@ namespace
dht_immutable_table_t::const_iterator i = m_immutable_table.find(target); dht_immutable_table_t::const_iterator i = m_immutable_table.find(target);
if (i == m_immutable_table.end()) return false; 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; return true;
} }
void put_immutable_item(sha1_hash const& target void put_immutable_item(sha1_hash const& target
, char const* buf, int size , span<char const> buf
, address const& addr) override , address const& addr) override
{ {
TORRENT_ASSERT(!m_node_ids.empty()); TORRENT_ASSERT(!m_node_ids.empty());
@ -367,17 +352,16 @@ namespace
, m_immutable_table); , m_immutable_table);
TORRENT_ASSERT(j != m_immutable_table.end()); TORRENT_ASSERT(j != m_immutable_table.end());
free(j->second.value);
m_immutable_table.erase(j); m_immutable_table.erase(j);
m_counters.immutable_data -= 1; m_counters.immutable_data -= 1;
} }
dht_immutable_item to_add; dht_immutable_item to_add;
to_add.value = static_cast<char*>(malloc(size)); to_add.value.reset(new char[buf.size()]);
to_add.size = size; to_add.size = int(buf.size());
memcpy(to_add.value, buf, size); memcpy(to_add.value.get(), buf.data(), buf.size());
std::tie(i, std::ignore) = m_immutable_table.insert( 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; m_counters.immutable_data += 1;
} }
@ -387,7 +371,7 @@ namespace
} }
bool get_mutable_item_seq(sha1_hash const& target 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); dht_mutable_table_t::const_iterator i = m_mutable_table.find(target);
if (i == m_mutable_table.end()) return false; if (i == m_mutable_table.end()) return false;
@ -397,29 +381,29 @@ namespace
} }
bool get_mutable_item(sha1_hash const& target 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 , entry& item) const override
{ {
dht_mutable_table_t::const_iterator i = m_mutable_table.find(target); dht_mutable_table_t::const_iterator i = m_mutable_table.find(target);
if (i == m_mutable_table.end()) return false; if (i == m_mutable_table.end()) return false;
dht_mutable_item const& f = i->second; dht_mutable_item const& f = i->second;
item["seq"] = f.seq; item["seq"] = f.seq.value;
if (force_fill || (0 <= seq && seq < f.seq)) if (force_fill || (sequence_number(0) <= seq && seq < f.seq))
{ {
item["v"] = bdecode(f.value, f.value + f.size); item["v"] = bdecode(f.value.get(), f.value.get() + f.size);
item["sig"] = std::string(f.sig, f.sig + sizeof(f.sig)); item["sig"] = f.sig.bytes;
item["k"] = std::string(f.key.bytes, f.key.bytes + sizeof(f.key.bytes)); item["k"] = f.key.bytes;
} }
return true; return true;
} }
void put_mutable_item(sha1_hash const& target void put_mutable_item(sha1_hash const& target
, char const* buf, int size , span<char const> buf
, char const* sig , signature const& sig
, std::int64_t seq , sequence_number seq
, char const* pk , public_key const& pk
, char const* salt, int salt_size , span<char const> salt
, address const& addr) override , address const& addr) override
{ {
TORRENT_ASSERT(!m_node_ids.empty()); TORRENT_ASSERT(!m_node_ids.empty());
@ -434,47 +418,37 @@ namespace
, m_mutable_table); , m_mutable_table);
TORRENT_ASSERT(j != m_mutable_table.end()); TORRENT_ASSERT(j != m_mutable_table.end());
free(j->second.value);
free(j->second.salt);
m_mutable_table.erase(j); m_mutable_table.erase(j);
m_counters.mutable_data -= 1; m_counters.mutable_data -= 1;
} }
dht_mutable_item to_add; dht_mutable_item to_add;
to_add.value = static_cast<char*>(malloc(size)); to_add.value.reset(new char[buf.size()]);
to_add.size = size; to_add.size = int(buf.size());
to_add.seq = seq; to_add.seq = seq;
to_add.salt = nullptr; to_add.salt.assign(salt.data(), salt.size());
to_add.salt_size = 0; to_add.sig = sig;
if (salt_size > 0) to_add.key = pk;
{ memcpy(to_add.value.get(), buf.data(), buf.size());
to_add.salt = static_cast<char*>(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));
std::tie(i, std::ignore) = m_mutable_table.insert( 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; m_counters.mutable_data += 1;
} }
else else
{ {
// this is the case where we already // 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.reset(new char[buf.size()]);
item->value = static_cast<char*>(malloc(size)); item.size = int(buf.size());
item->size = size;
} }
item->seq = seq; item.seq = seq;
memcpy(item->sig, sig, sizeof(item->sig)); item.sig = sig;
memcpy(item->value, buf, size); memcpy(item.value.get(), buf.data(), buf.size());
} }
} }
@ -516,7 +490,6 @@ namespace
++i; ++i;
continue; continue;
} }
free(i->second.value);
m_immutable_table.erase(i++); m_immutable_table.erase(i++);
m_counters.immutable_data -= 1; m_counters.immutable_data -= 1;
} }
@ -529,8 +502,6 @@ namespace
++i; ++i;
continue; continue;
} }
free(i->second.value);
free(i->second.salt);
m_mutable_table.erase(i++); m_mutable_table.erase(i++);
m_counters.mutable_data -= 1; m_counters.mutable_data -= 1;
} }
@ -556,7 +527,7 @@ namespace
, end(peers.end()); i != end;) , end(peers.end()); i != end;)
{ {
// the peer has timed out // 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++); peers.erase(i++);
m_counters.peers -= 1; m_counters.peers -= 1;

View File

@ -444,7 +444,7 @@ namespace libtorrent { namespace dht
// key is a 32-byte binary string, the public key to look up. // key is a 32-byte binary string, the public key to look up.
// the salt is optional // the salt is optional
void dht_tracker::get_item(char const* key void dht_tracker::get_item(public_key const& key
, boost::function<void(item const&, bool)> cb , boost::function<void(item const&, bool)> cb
, std::string salt) , std::string salt)
{ {
@ -461,8 +461,7 @@ namespace libtorrent { namespace dht
{ {
std::string flat_data; std::string flat_data;
bencode(std::back_inserter(flat_data), data); bencode(std::back_inserter(flat_data), data);
sha1_hash target = item_target_id( sha1_hash const target = item_target_id(flat_data);
std::pair<char const*, int>(flat_data.c_str(), flat_data.size()));
boost::shared_ptr<put_item_ctx> boost::shared_ptr<put_item_ctx>
ctx = boost::make_shared<put_item_ctx>((TORRENT_USE_IPV6) ? 2 : 1); ctx = boost::make_shared<put_item_ctx>((TORRENT_USE_IPV6) ? 2 : 1);
@ -474,7 +473,7 @@ namespace libtorrent { namespace dht
#endif #endif
} }
void dht_tracker::put_item(char const* key void dht_tracker::put_item(public_key const& key
, boost::function<void(item const&, int)> cb , boost::function<void(item const&, int)> cb
, boost::function<void(item&)> data_cb, std::string salt) , boost::function<void(item&)> data_cb, std::string salt)
{ {

View File

@ -45,9 +45,9 @@ namespace libtorrent { namespace dht
{ {
void get_item::got_data(bdecode_node const& v, void get_item::got_data(bdecode_node const& v,
char const* pk, public_key const& pk,
std::uint64_t seq, sequence_number const seq,
char const* sig) signature const& sig)
{ {
// we received data! // we received data!
// if no data_callback, we needn't care about the data we get. // 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; return;
} }
// immutalbe data should has been handled before this line, only mutable // immutable data should have been handled before this line, only mutable
// data can reach here, which means pk and sig must be valid. // data can reach here, which means pk, sig and seq must be valid.
if (!pk || !sig) return;
std::string temp_copy(m_data.salt()); std::string const salt_copy(m_data.salt());
std::pair<char const*, int> salt(temp_copy.c_str(), int(temp_copy.size())); sha1_hash const incoming_target = item_target_id(salt_copy, pk);
sha1_hash incoming_target = item_target_id(salt, pk);
if (incoming_target != m_target) return; if (incoming_target != m_target) return;
// this is mutable data. If it passes the signature // 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. // the highest sequence number.
if (m_data.empty() || m_data.seq() < seq) 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; return;
// for get_item, we should call callback when we get data, // for get_item, we should call callback when we get data,
@ -114,13 +112,11 @@ get_item::get_item(
get_item::get_item( get_item::get_item(
node& dht_node node& dht_node
, char const* pk , public_key const& pk
, std::string const& salt , span<char const> salt
, data_callback const& dcallback , data_callback const& dcallback
, nodes_callback const& ncallback) , nodes_callback const& ncallback)
: find_data(dht_node, item_target_id( : find_data(dht_node, item_target_id(salt, pk), ncallback)
std::make_pair(salt.c_str(), int(salt.size())), pk)
, ncallback)
, m_data_callback(dcallback) , m_data_callback(dcallback)
, m_data(pk, salt) , m_data(pk, salt)
, m_immutable(false) , m_immutable(false)
@ -172,10 +168,7 @@ void get_item::done()
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
if (m_data.is_mutable()) if (m_data.is_mutable())
{ {
TORRENT_ASSERT(m_target TORRENT_ASSERT(m_target == item_target_id(m_data.salt(), m_data.pk()));
== item_target_id(std::pair<char const*, int>(m_data.salt().c_str()
, m_data.salt().size())
, m_data.pk().data()));
} }
#endif #endif
} }
@ -185,9 +178,9 @@ void get_item::done()
void get_item_observer::reply(msg const& m) void get_item_observer::reply(msg const& m)
{ {
char const* pk = nullptr; public_key pk;
char const* sig = nullptr; signature sig;
std::uint64_t seq = 0; sequence_number seq{0};
bdecode_node r = m.message.dict_find_dict("r"); bdecode_node r = m.message.dict_find_dict("r");
if (!r) if (!r)
@ -201,17 +194,19 @@ void get_item_observer::reply(msg const& m)
} }
bdecode_node k = r.dict_find_string("k"); bdecode_node k = r.dict_find_string("k");
if (k && k.string_length() == item_pk_len) if (k && k.string_length() == public_key::len)
pk = k.string_ptr(); std::memcpy(pk.bytes.data(), k.string_ptr(), public_key::len);
bdecode_node s = r.dict_find_string("sig"); bdecode_node s = r.dict_find_string("sig");
if (s && s.string_length() == item_sig_len) if (s && s.string_length() == signature::len)
sig = s.string_ptr(); std::memcpy(sig.bytes.data(), s.string_ptr(), signature::len);
bdecode_node q = r.dict_find_int("seq"); bdecode_node q = r.dict_find_int("seq");
if (q) if (q)
seq = q.int_value(); {
else if (pk && sig) seq = sequence_number(q.int_value());
}
else if (k && s)
{ {
timeout(); timeout();
return; return;

View File

@ -33,10 +33,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/hasher.hpp> #include <libtorrent/hasher.hpp>
#include <libtorrent/kademlia/item.hpp> #include <libtorrent/kademlia/item.hpp>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
#include <libtorrent/span.hpp>
#include <libtorrent/ed25519.hpp> #include <libtorrent/ed25519.hpp>
#include <cstdio> // for snprintf #include <cstdio> // for snprintf
#include <cinttypes> // for PRId64 et.al. #include <cinttypes> // for PRId64 et.al.
#include <cstring> // for memcpy
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
#include "libtorrent/bdecode.hpp" #include "libtorrent/bdecode.hpp"
@ -47,67 +49,67 @@ namespace libtorrent { namespace dht
namespace namespace
{ {
enum { canonical_length = 1200 }; int canonical_string(span<char const> v
int canonical_string(std::pair<char const*, int> v, std::uint64_t seq , sequence_number const seq
, std::pair<char const*, int> salt, char out[canonical_length]) , span<char const> salt
, span<char> out)
{ {
// v must be valid bencoding! // v must be valid bencoding!
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
bdecode_node e; bdecode_node e;
error_code ec; 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 #endif
char* ptr = out; char* ptr = out.data();
int left = canonical_length - (ptr - out); size_t left = out.size() - (ptr - out.data());
if (salt.second > 0) if (salt.size() > 0)
{ {
ptr += std::snprintf(ptr, left, "4:salt%d:", salt.second); ptr += std::snprintf(ptr, left, "4:salt%d:", int(salt.size()));
left = canonical_length - (ptr - out); left = out.size() - (ptr - out.data());
memcpy(ptr, salt.first, (std::min)(salt.second, left)); std::memcpy(ptr, salt.data(), (std::min)(salt.size(), left));
ptr += (std::min)(salt.second, left); ptr += (std::min)(salt.size(), left);
left = canonical_length - (ptr - out); left = out.size() - (ptr - out.data());
} }
ptr += std::snprintf(ptr, canonical_length - (ptr - out) ptr += std::snprintf(ptr, out.size() - (ptr - out.data())
, "3:seqi%" PRId64 "e1:v", seq); , "3:seqi%" PRId64 "e1:v", seq.value);
left = canonical_length - (ptr - out); left = out.size() - (ptr - out.data());
memcpy(ptr, v.first, (std::min)(v.second, left)); std::memcpy(ptr, v.data(), (std::min)(v.size(), left));
ptr += (std::min)(v.second, left); ptr += (std::min)(v.size(), left);
TORRENT_ASSERT((ptr - out) <= canonical_length); TORRENT_ASSERT((ptr - out.data()) <= out.size());
return ptr - out; return ptr - out.data();
} }
} }
// calculate the target hash for an immutable item. // calculate the target hash for an immutable item.
sha1_hash item_target_id(std::pair<char const*, int> v) sha1_hash item_target_id(span<char const> v)
{ {
return hasher(v.first, v.second).final(); return hasher(v).final();
} }
// calculate the target hash for a mutable item. // calculate the target hash for a mutable item.
sha1_hash item_target_id(std::pair<char const*, int> salt sha1_hash item_target_id(span<char const> salt
, char const* pk) , public_key const& pk)
{ {
hasher h; hasher h(pk.bytes);
h.update(pk, item_pk_len); if (salt.size() > 0) h.update(salt);
if (salt.second > 0) h.update(salt.first, salt.second);
return h.final(); return h.final();
} }
bool verify_mutable_item( bool verify_mutable_item(
std::pair<char const*, int> v span<char const> v
, std::pair<char const*, int> salt , span<char const> salt
, std::uint64_t seq , sequence_number const seq
, char const* pk , public_key const& pk
, char const* sig) , signature const& sig)
{ {
char str[canonical_length]; char str[1200];
int len = canonical_string(v, seq, salt, str); int len = canonical_string(v, seq, salt, str);
return ed25519_verify(reinterpret_cast<unsigned char const*>(sig) return ed25519_verify(reinterpret_cast<unsigned char const*>(sig.bytes.data())
, reinterpret_cast<unsigned char const*>(str) , reinterpret_cast<unsigned char const*>(str)
, len , len
, reinterpret_cast<unsigned char const*>(pk)) == 1; , reinterpret_cast<unsigned char const*>(pk.bytes.data())) == 1;
} }
// given the bencoded buffer ``v``, the salt (which is optional and may have // 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 // at least 64 bytes of available space. This space is where the signature is
// written. // written.
void sign_mutable_item( void sign_mutable_item(
std::pair<char const*, int> v span<char const> v
, std::pair<char const*, int> salt , span<char const> salt
, std::uint64_t seq , sequence_number const seq
, char const* pk , public_key const& pk
, char const* sk , secret_key const& sk
, char* sig) , signature& sig)
{ {
char str[canonical_length]; char str[1200];
int len = canonical_string(v, seq, salt, str); int const len = canonical_string(v, seq, salt, str);
ed25519_sign(reinterpret_cast<unsigned char*>(sig) ed25519_sign(reinterpret_cast<unsigned char*>(sig.bytes.data())
, reinterpret_cast<unsigned char const*>(str) , reinterpret_cast<unsigned char const*>(str)
, len , len
, reinterpret_cast<unsigned char const*>(pk) , reinterpret_cast<unsigned char const*>(pk.bytes.data())
, reinterpret_cast<unsigned char const*>(sk) , reinterpret_cast<unsigned char const*>(sk.bytes.data())
); );
} }
item::item(char const* pk, std::string const& salt) item::item(public_key const& pk, span<char const> salt)
: m_salt(salt) : m_salt(salt.data(), salt.size())
, m_pk(pk)
, m_seq(0) , m_seq(0)
, m_mutable(true) , 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<char const> 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 void item::assign(entry v)
, std::pair<char const*, int> salt
, std::uint64_t seq, char const* pk, char const* sk)
{ {
assign(v, salt, seq, pk, sk); m_mutable = false;
m_value = std::move(v);
} }
void item::assign(entry const& v, std::pair<char const*, int> salt void item::assign(entry v, span<char const> salt
, std::uint64_t seq, char const* pk, char const* sk) , sequence_number const seq, public_key const& pk, secret_key const& sk)
{ {
m_value = v;
if (pk && sk)
{
char buffer[1000]; char buffer[1000];
int bsize = bencode(buffer, v); int bsize = bencode(buffer, v);
TORRENT_ASSERT(bsize <= 1000); TORRENT_ASSERT(bsize <= 1000);
sign_mutable_item(std::make_pair(buffer, bsize) sign_mutable_item(span<char const>(buffer, bsize)
, salt, seq, pk, sk, m_sig.data()); , salt, seq, pk, sk, m_sig);
m_salt.assign(salt.first, salt.second); m_salt.assign(salt.data(), salt.size());
memcpy(m_pk.data(), pk, item_pk_len); m_pk = pk;
m_seq = seq; m_seq = seq;
m_mutable = true; m_mutable = true;
} m_value = std::move(v);
else
m_mutable = false;
} }
bool item::assign(bdecode_node const& v void item::assign(bdecode_node const& v)
, std::pair<char const*, int> salt
, std::uint64_t seq, char const* pk, char const* sig)
{ {
TORRENT_ASSERT(v.data_section().second <= 1000); m_mutable = false;
if (pk && sig) m_value = v;
{ }
bool item::assign(bdecode_node const& v, span<char const> salt
, sequence_number const seq, public_key const& pk, signature const& sig)
{
TORRENT_ASSERT(v.data_section().size() <= 1000);
if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig)) if (!verify_mutable_item(v.data_section(), salt, seq, pk, sig))
return false; return false;
memcpy(m_pk.data(), pk, item_pk_len); m_pk = pk;
memcpy(m_sig.data(), sig, item_sig_len); m_sig = sig;
if (salt.second > 0) if (salt.size() > 0)
m_salt.assign(salt.first, salt.second); m_salt.assign(salt.data(), salt.size());
else else
m_salt.clear(); m_salt.clear();
m_seq = seq; m_seq = seq;
m_mutable = true; m_mutable = true;
}
else
m_mutable = false;
m_value = v; m_value = v;
return true; return true;
} }
void item::assign(entry const& v, std::string salt, std::uint64_t seq void item::assign(entry v, span<char const> salt
, char const* pk, char const* sig) , 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); m_pk = pk;
memcpy(m_sig.data(), sig, item_sig_len); m_sig = sig;
m_salt = salt; m_salt.assign(salt.data(), salt.size());
m_seq = seq; m_seq = seq;
m_mutable = true; m_mutable = true;
m_value = v; m_value = std::move(v);
} }
} } // namespace libtorrent::dht } } // namespace libtorrent::dht

View File

@ -145,7 +145,7 @@ void node::update_node_id()
m_table.update_node_id(m_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 , udp::endpoint const& addr) const
{ {
if (token.length() != 4) if (token.length() != 4)
@ -166,7 +166,7 @@ bool node::verify_token(std::string const& token, char const* info_hash
if (ec) return false; if (ec) return false;
h1.update(address); h1.update(address);
h1.update(reinterpret_cast<char const*>(&m_secret[0]), sizeof(m_secret[0])); h1.update(reinterpret_cast<char const*>(&m_secret[0]), sizeof(m_secret[0]));
h1.update(info_hash, 20); h1.update(info_hash);
sha1_hash h = h1.final(); sha1_hash h = h1.final();
if (std::equal(token.begin(), token.end(), reinterpret_cast<char*>(&h[0]))) if (std::equal(token.begin(), token.end(), reinterpret_cast<char*>(&h[0])))
@ -175,7 +175,7 @@ bool node::verify_token(std::string const& token, char const* info_hash
hasher h2; hasher h2;
h2.update(address); h2.update(address);
h2.update(reinterpret_cast<char const*>(&m_secret[1]), sizeof(m_secret[1])); h2.update(reinterpret_cast<char const*>(&m_secret[1]), sizeof(m_secret[1]));
h2.update(info_hash, 20); h2.update(info_hash);
h = h2.final(); h = h2.final();
if (std::equal(token.begin(), token.end(), reinterpret_cast<char*>(&h[0]))) if (std::equal(token.begin(), token.end(), reinterpret_cast<char*>(&h[0])))
return true; 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 std::string node::generate_token(udp::endpoint const& addr
, char const* info_hash) , sha1_hash const& info_hash)
{ {
std::string token; std::string token;
token.resize(4); token.resize(4);
@ -193,7 +193,7 @@ std::string node::generate_token(udp::endpoint const& addr
TORRENT_ASSERT(!ec); TORRENT_ASSERT(!ec);
h.update(address); h.update(address);
h.update(reinterpret_cast<char*>(&m_secret[0]), sizeof(m_secret[0])); h.update(reinterpret_cast<char*>(&m_secret[0]), sizeof(m_secret[0]));
h.update(info_hash, 20); h.update(info_hash);
sha1_hash const hash = h.final(); sha1_hash const hash = h.final();
std::copy(hash.begin(), hash.begin() + 4, reinterpret_cast<char*>(&token[0])); std::copy(hash.begin(), hash.begin() + 4, reinterpret_cast<char*>(&token[0]));
@ -360,7 +360,7 @@ namespace
if (node.observer()) if (node.observer())
{ {
char hex_ih[41]; char hex_ih[41];
aux::to_hex(reinterpret_cast<char const*>(&ih[0]), 20, hex_ih); aux::to_hex(ih.data(), 20, hex_ih);
node.observer()->log(dht_logger::node, "sending announce_peer [ ih: %s " node.observer()->log(dht_logger::node, "sending announce_peer [ ih: %s "
" p: %d nodes: %d ]", hex_ih, listen_port, int(v.size())); " p: %d nodes: %d ]", hex_ih, listen_port, int(v.size()));
} }
@ -391,7 +391,7 @@ namespace
e["y"] = "q"; e["y"] = "q";
e["q"] = "announce_peer"; e["q"] = "announce_peer";
entry& a = e["a"]; entry& a = e["a"];
a["info_hash"] = ih.to_string(); a["info_hash"] = ih;
a["port"] = listen_port; a["port"] = listen_port;
a["token"] = i->second; a["token"] = i->second;
a["seed"] = (flags & node::flag_seed) ? 1 : 0; 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) if (m_observer)
{ {
char hex_ih[41]; char hex_ih[41];
aux::to_hex(reinterpret_cast<char const*>(&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 ]" m_observer->log(dht_logger::node, "announcing [ ih: %s p: %d ]"
, hex_ih, listen_port); , hex_ih, listen_port);
} }
@ -484,7 +484,7 @@ void node::get_item(sha1_hash const& target
if (m_observer) if (m_observer)
{ {
char hex_target[41]; char hex_target[41];
aux::to_hex(reinterpret_cast<char const*>(&target[0]), 20, hex_target); aux::to_hex(target.data(), 20, hex_target);
m_observer->log(dht_logger::node, "starting get for [ hash: %s ]" m_observer->log(dht_logger::node, "starting get for [ hash: %s ]"
, hex_target); , hex_target);
} }
@ -495,14 +495,14 @@ void node::get_item(sha1_hash const& target
ta->start(); 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<void(item const&, bool)> f) , boost::function<void(item const&, bool)> f)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (m_observer) if (m_observer)
{ {
char hex_key[65]; 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); m_observer->log(dht_logger::node, "starting get for [ key: %s ]", hex_key);
} }
#endif #endif
@ -559,7 +559,7 @@ void node::put_item(sha1_hash const& target, entry const& data, boost::function<
ta->start(); 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<void(item const&, int)> f , boost::function<void(item const&, int)> f
, boost::function<void(item&)> data_cb) , boost::function<void(item&)> data_cb)
{ {
@ -567,7 +567,7 @@ void node::put_item(char const* pk, std::string const& salt
if (m_observer) if (m_observer)
{ {
char hex_key[65]; 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); m_observer->log(dht_logger::node, "starting get for [ key: %s ]", hex_key);
} }
#endif #endif
@ -866,7 +866,7 @@ void node::incoming_request(msg const& m, entry& e)
return; return;
} }
reply["token"] = generate_token(m.addr, msg_keys[0].string_ptr()); reply["token"] = generate_token(m.addr, sha1_hash(msg_keys[0].string_ptr()));
m_counters.inc_stats_counter(counters::dht_get_peers_in); m_counters.inc_stats_counter(counters::dht_get_peers_in);
@ -944,7 +944,8 @@ void node::incoming_request(msg const& m, entry& e)
if (m_observer) if (m_observer)
m_observer->announce(info_hash, m.addr.address(), port); 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); m_counters.inc_stats_counter(counters::dht_invalid_announce);
incoming_error(e, "invalid token"); 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}, {"v", bdecode_node::none_t, 0, 0},
{"seq", bdecode_node::int_t, 0, key_desc_t::optional}, {"seq", bdecode_node::int_t, 0, key_desc_t::optional},
// public key // public key
{"k", bdecode_node::string_t, item_pk_len, key_desc_t::optional}, {"k", bdecode_node::string_t, public_key::len, key_desc_t::optional},
{"sig", bdecode_node::string_t, item_sig_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}, {"cas", bdecode_node::int_t, 0, key_desc_t::optional},
{"salt", bdecode_node::string_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]); bool mutable_put = (msg_keys[2] && msg_keys[3] && msg_keys[4]);
// public key (only set if it's a mutable put) // public key (only set if it's a mutable put)
char const* pk = nullptr; char const* pub_key = nullptr;
if (msg_keys[3]) pk = msg_keys[3].string_ptr(); if (msg_keys[3]) pub_key = msg_keys[3].string_ptr();
// signature (only set if it's a mutable put) // signature (only set if it's a mutable put)
char const* sig = nullptr; char const* sign = nullptr;
if (msg_keys[4]) sig = msg_keys[4].string_ptr(); if (msg_keys[4]) sign = msg_keys[4].string_ptr();
// pointer and length to the whole entry // pointer and length to the whole entry
std::pair<char const*, int> buf = msg_keys[1].data_section(); span<char const> buf = msg_keys[1].data_section();
if (buf.second > 1000 || buf.second <= 0) if (buf.size() > 1000 || buf.size() <= 0)
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "message too big", 205); incoming_error(e, "message too big", 205);
return; return;
} }
std::pair<char const*, int> salt(static_cast<char const*>(nullptr), 0); span<char const> salt;
if (msg_keys[6]) if (msg_keys[6])
salt = std::pair<char const*, int>( salt = { msg_keys[6].string_ptr(), size_t(msg_keys[6].string_length()) };
msg_keys[6].string_ptr(), msg_keys[6].string_length()); if (salt.size() > 64)
if (salt.second > 64)
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "salt too big", 207); incoming_error(e, "salt too big", 207);
return; return;
} }
sha1_hash target; sha1_hash const target = pub_key
if (pk) ? item_target_id(salt, public_key(pub_key))
target = item_target_id(salt, pk); : item_target_id(buf);
else
target = item_target_id(buf);
// std::fprintf(stderr, "%s PUT target: %s salt: %s key: %s\n" // std::fprintf(stderr, "%s PUT target: %s salt: %s key: %s\n"
// , mutable_put ? "mutable":"immutable" // , 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 // verify the write-token. tokens are only valid to write to
// specific target hashes. it must match the one we got a "get" for // specific target hashes. it must match the one we got a "get" for
if (!verify_token(msg_keys[0].string_value() if (!verify_token(msg_keys[0].string_value(), target, m.addr))
, reinterpret_cast<char const*>(&target[0]), m.addr))
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "invalid token"); incoming_error(e, "invalid token");
@ -1045,14 +1042,16 @@ void node::incoming_request(msg const& m, entry& e)
if (!mutable_put) 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 else
{ {
// mutable put, we must verify the signature // 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); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "invalid (negative) sequence number"); 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 // msg_keys[4] is the signature, msg_keys[3] is the public key
if (!verify_mutable_item(buf, salt if (!verify_mutable_item(buf, salt, seq, pk, sig))
, seq, pk, sig))
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "invalid signature", 206); incoming_error(e, "invalid signature", 206);
return; 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)) if (!m_storage.get_mutable_item_seq(target, item_seq))
{ {
m_storage.put_mutable_item(target m_storage.put_mutable_item(target, buf, sig, seq, pk, salt
, buf.first, buf.second
, sig, seq, pk
, salt.first, salt.second
, m.addr.address()); , m.addr.address());
} }
else else
@ -1086,7 +1081,7 @@ void node::incoming_request(msg const& m, entry& e)
// number matches the expected value before replacing it // number matches the expected value before replacing it
// this is critical for avoiding race conditions when multiple // this is critical for avoiding race conditions when multiple
// writers are accessing the same slot // writers are accessing the same slot
if (msg_keys[5] && item_seq != msg_keys[5].int_value()) if (msg_keys[5] && item_seq.value != msg_keys[5].int_value())
{ {
m_counters.inc_stats_counter(counters::dht_invalid_put); m_counters.inc_stats_counter(counters::dht_invalid_put);
incoming_error(e, "CAS mismatch", 301); incoming_error(e, "CAS mismatch", 301);
@ -1100,10 +1095,7 @@ void node::incoming_request(msg const& m, entry& e)
return; return;
} }
m_storage.put_mutable_item(target m_storage.put_mutable_item(target, buf, sig, seq, pk, salt
, buf.first, buf.second
, sig, seq, pk
, salt.first, salt.second
, m.addr.address()); , m.addr.address());
} }
} }
@ -1137,7 +1129,7 @@ void node::incoming_request(msg const& m, entry& e)
// , msg_keys[1] ? "mutable":"immutable" // , msg_keys[1] ? "mutable":"immutable"
// , aux::to_hex(target.to_string()).c_str()); // , 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 // always return nodes as well as peers
write_nodes_entries(target, msg_keys[2], reply); 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 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 else
{ {
m_storage.get_mutable_item(target m_storage.get_mutable_item(target
, msg_keys[0].int_value(), false , sequence_number(msg_keys[0].int_value()), false
, reply); , reply);
} }
} }

View File

@ -106,9 +106,9 @@ bool put_data::invoke(observer_ptr o)
a["token"] = po->m_token; a["token"] = po->m_token;
if (m_data.is_mutable()) if (m_data.is_mutable())
{ {
a["k"] = std::string(m_data.pk().data(), item_pk_len); a["k"] = m_data.pk().bytes;
a["seq"] = m_data.seq(); a["seq"] = m_data.seq().value;
a["sig"] = std::string(m_data.sig().data(), item_sig_len); a["sig"] = m_data.sig().bytes;
if (!m_data.salt().empty()) if (!m_data.salt().empty())
{ {
a["salt"] = m_data.salt(); a["salt"] = m_data.salt();

View File

@ -96,11 +96,9 @@ namespace libtorrent
std::array<char, 96> buffer; std::array<char, 96> buffer;
mp::export_bits(m_dh_shared_secret, reinterpret_cast<std::uint8_t*>(buffer.data()), 8); mp::export_bits(m_dh_shared_secret, reinterpret_cast<std::uint8_t*>(buffer.data()), 8);
static char const req3[4] = {'r', 'e', 'q', '3'};
// calculate the xor mask for the obfuscated hash // calculate the xor mask for the obfuscated hash
hasher h; m_xor_mask = hasher(req3).update(buffer).final();
h.update("req3", 4);
h.update(buffer);
m_xor_mask = h.final();
} }
std::tuple<int, span<aux::const_buffer>> std::tuple<int, span<aux::const_buffer>>
@ -148,7 +146,7 @@ namespace libtorrent
if (num_bufs != 0) if (num_bufs != 0)
{ {
std::tie(next_barrier, out_iovec) 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) if (m_send_barriers.front().next != INT_MAX)

View File

@ -97,8 +97,7 @@ namespace libtorrent
{ {
// verify the info-hash of the metadata stored in the resume file matches // verify the info-hash of the metadata stored in the resume file matches
// the torrent we're loading // the torrent we're loading
sha1_hash const resume_ih = hasher(info.data_section().first sha1_hash const resume_ih = hasher(info.data_section()).final();
, info.data_section().second).final();
// if url is set, the info_hash is not actually the info-hash of the // if url is set, the info_hash is not actually the info-hash of the
// torrent, but the hash of the URL, until we have the full torrent // torrent, but the hash of the URL, until we have the full torrent

View File

@ -521,6 +521,8 @@ namespace libtorrent
#endif #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) sha1_hash session_handle::dht_put_item(entry data)
{ {
std::vector<char> buf; std::vector<char> buf;

View File

@ -81,6 +81,7 @@ const rlim_t rlim_infinity = RLIM_INFINITY;
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
#include "libtorrent/kademlia/dht_tracker.hpp" #include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/kademlia/types.hpp"
#endif #endif
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
@ -4716,9 +4717,9 @@ namespace aux {
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size()); TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
hasher h; static char const req2[4] = {'r', 'e', 'q', '2'};
h.update("req2", 4); hasher h(req2);
h.update(params.info_hash.data(), 20); h.update(params.info_hash);
// this is SHA1("req2" + info-hash), used for // this is SHA1("req2" + info-hash), used for
// encrypted hand shakes // encrypted hand shakes
m_obfuscated_torrents.insert(std::make_pair(h.final(), torrent_ptr)); 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()) if (i == m_torrents.end() && !tptr->url().empty())
{ {
std::string const& url = tptr->url(); std::string const& url = tptr->url();
sha1_hash urlhash = hasher(&url[0], int(url.size())).final(); i = m_torrents.find(hasher(url).final());
i = m_torrents.find(urlhash);
} }
#endif #endif
@ -5085,9 +5085,9 @@ namespace aux {
TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size()); TORRENT_ASSERT(m_torrents.size() >= m_torrent_lru.size());
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
hasher h; static char const req2[4] = {'r', 'e', 'q', '2'};
h.update("req2", 4); hasher h(req2);
h.update(tptr->info_hash().data(), 20); h.update(tptr->info_hash());
m_obfuscated_torrents.erase(h.final()); m_obfuscated_torrents.erase(h.final());
#endif #endif
@ -5714,20 +5714,23 @@ namespace aux {
} }
// callback for dht_mutable_get // 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()); TORRENT_ASSERT(i.is_mutable());
m_alerts.emplace_alert<dht_mutable_item_alert>(i.pk(), i.sig(), i.seq() m_alerts.emplace_alert<dht_mutable_item_alert>(i.pk().bytes
, i.sig().bytes, i.seq().value
, i.salt(), i.value(), authoritative); , i.salt(), i.value(), authoritative);
} }
// key is a 32-byte binary string, the public key to look up. // key is a 32-byte binary string, the public key to look up.
// the salt is optional // the salt is optional
// TODO: 3 use public_key here instead of std::array
void session_impl::dht_get_mutable_item(std::array<char, 32> key void session_impl::dht_get_mutable_item(std::array<char, 32> key
, std::string salt) , std::string salt)
{ {
if (!m_dht) return; 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); , 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) void on_dht_put_mutable_item(alert_manager& alerts, dht::item const& i, int num)
{ {
std::array<char, 64> sig = i.sig(); dht::signature sig = i.sig();
std::array<char, 32> pk = i.pk(); dht::public_key pk = i.pk();
std::uint64_t seq = i.seq(); dht::sequence_number seq = i.seq();
std::string salt = i.salt(); std::string salt = i.salt();
if (alerts.should_post<dht_put_alert>()) if (alerts.should_post<dht_put_alert>())
alerts.emplace_alert<dht_put_alert>(pk, sig, salt, seq, num); {
alerts.emplace_alert<dht_put_alert>(pk.bytes, sig.bytes, salt
, seq.value, num);
}
} }
void put_mutable_callback(dht::item& i void put_mutable_callback(dht::item& i
, boost::function<void(entry&, std::array<char,64>& , boost::function<void(entry&, std::array<char, 64>&
, std::uint64_t&, std::string const&)> cb) , std::uint64_t&, std::string const&)> cb)
{ {
entry value = i.value(); entry value = i.value();
std::array<char, 64> sig = i.sig(); dht::signature sig = i.sig();
std::array<char, 32> pk = i.pk(); dht::public_key pk = i.pk();
std::uint64_t seq = i.seq(); dht::sequence_number seq = i.seq();
std::string salt = i.salt(); std::string salt = i.salt();
cb(value, sig, seq, salt); cb(value, sig.bytes, seq.value, salt);
i.assign(value, salt, seq, pk.data(), sig.data()); i.assign(std::move(value), salt, seq, pk, sig);
} }
void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers) void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers)
@ -5792,9 +5798,9 @@ namespace aux {
, std::string salt) , std::string salt)
{ {
if (!m_dht) return; if (!m_dht) return;
m_dht->put_item(key.data(), m_dht->put_item(dht::public_key(key.data())
std::bind(&on_dht_put_mutable_item, boost::ref(m_alerts), _1, _2), , std::bind(&on_dht_put_mutable_item, boost::ref(m_alerts), _1, _2)
std::bind(&put_mutable_callback, _1, cb), salt); , std::bind(&put_mutable_callback, _1, cb), salt);
} }
void session_impl::dht_get_peers(sha1_hash const& info_hash) void session_impl::dht_get_peers(sha1_hash const& info_hash)

View File

@ -195,7 +195,7 @@ namespace
h.update(j->buffer.disk_block, j->d.io.buffer_size); h.update(j->buffer.disk_block, j->d.io.buffer_size);
h.update(reinterpret_cast<char const*>(&m_salt), sizeof(m_salt)); h.update(reinterpret_cast<char const*>(&m_salt), sizeof(m_salt));
std::pair<peer_list::iterator, peer_list::iterator> range std::pair<peer_list::iterator, peer_list::iterator> const range
= m_torrent.find_peers(a); = m_torrent.find_peers(a);
// there is no peer with this address anymore // there is no peer with this address anymore
@ -270,7 +270,7 @@ namespace
hasher h; hasher h;
h.update(j->buffer.disk_block, j->d.io.buffer_size); h.update(j->buffer.disk_block, j->d.io.buffer_size);
h.update(reinterpret_cast<char const*>(&m_salt), sizeof(m_salt)); h.update(reinterpret_cast<char const*>(&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; if (b.second.digest == ok_digest) return;

View File

@ -537,8 +537,8 @@ namespace libtorrent
m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end()); m_web_seeds.insert(m_web_seeds.end(), web_seeds.begin(), web_seeds.end());
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
hasher h; static char const req2[4] = {'r', 'e', 'q', '2'};
h.update("req2", 4); hasher h(req2);
h.update(m_torrent_file->info_hash()); h.update(m_torrent_file->info_hash());
m_ses.add_obfuscated_hash(h.final(), shared_from_this()); m_ses.add_obfuscated_hash(h.final(), shared_from_this());
#endif #endif
@ -7011,6 +7011,7 @@ namespace libtorrent
return peerinfo->connection != nullptr; return peerinfo->connection != nullptr;
} }
// TODO: 3 make this take a span<char const> instead
bool torrent::set_metadata(char const* metadata_buf, int metadata_size) bool torrent::set_metadata(char const* metadata_buf, int metadata_size)
{ {
TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(is_single_thread());
@ -7031,7 +7032,8 @@ namespace libtorrent
bdecode_node metadata; bdecode_node metadata;
error_code ec; 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)) if (ret != 0 || !m_torrent_file->parse_info_section(metadata, ec, 0))
{ {
update_gauge(); update_gauge();

View File

@ -1050,28 +1050,25 @@ namespace libtorrent
} }
// hash the info-field to calculate info-hash // hash the info-field to calculate info-hash
hasher h; auto section = info.data_section();
std::pair<char const*, int> section = info.data_section(); m_info_hash = hasher(section).final();
h.update(section.first, section.second); if (info.data_section().size() >= (std::numeric_limits<std::uint32_t>::max)())
m_info_hash = h.final();
if (section.second >= (std::numeric_limits<std::uint32_t>::max)())
{ {
ec = errors::metadata_too_large; ec = errors::metadata_too_large;
return false; return false;
} }
// copy the info section // 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]); m_info_section.reset(new char[m_info_section_size]);
std::memcpy(m_info_section.get(), section.first, m_info_section_size); std::memcpy(m_info_section.get(), section.data(), m_info_section_size);
TORRENT_ASSERT(section.first[0] == 'd'); TORRENT_ASSERT(section[0] == 'd');
TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e'); TORRENT_ASSERT(section[m_info_section_size-1] == 'e');
// when translating a pointer that points into the 'info' tree's // when translating a pointer that points into the 'info' tree's
// backing buffer, into a pointer to our copy of the info section, // backing buffer, into a pointer to our copy of the info section,
// this is the pointer offset to use. // 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 // extract piece length
int piece_length = info.dict_find_int_value("piece length", -1); int piece_length = info.dict_find_int_value("piece length", -1);

View File

@ -143,6 +143,7 @@ test-suite libtorrent :
[ run test_dht.cpp [ run test_dht.cpp
test_dht_storage.cpp test_dht_storage.cpp
test_direct_dht.cpp
] ]
[ run test_string.cpp [ run test_string.cpp
@ -154,7 +155,6 @@ test-suite libtorrent :
[ run test_crc32.cpp ] [ run test_crc32.cpp ]
[ run test_receive_buffer.cpp ] [ run test_receive_buffer.cpp ]
[ run test_alert_manager.cpp ] [ run test_alert_manager.cpp ]
[ run test_direct_dht.cpp ]
[ run test_magnet.cpp ] [ run test_magnet.cpp ]
[ run test_storage.cpp ] [ run test_storage.cpp ]
[ run test_session.cpp ] [ run test_session.cpp ]

View File

@ -42,13 +42,13 @@ TORRENT_TEST(integer)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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::printf("%s\n", print_entry(e).c_str());
std::pair<const char*, int> section = e.data_section(); span<const char> section = e.data_section();
TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0);
TEST_CHECK(section.second == sizeof(b) - 1); TEST_EQUAL(section.size(), sizeof(b) - 1);
TEST_CHECK(e.type() == bdecode_node::int_t); TEST_EQUAL(e.type(), bdecode_node::int_t);
TEST_CHECK(e.int_value() == 12453); TEST_EQUAL(e.int_value(), 12453);
} }
// test string // test string
@ -58,11 +58,11 @@ TORRENT_TEST(string)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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::printf("%s\n", print_entry(e).c_str());
std::pair<const char*, int> section = e.data_section(); span<const char> section = e.data_section();
TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0);
TEST_EQUAL(section.second, sizeof(b) - 1); TEST_EQUAL(section.size(), sizeof(b) - 1);
TEST_EQUAL(e.type(), bdecode_node::string_t); TEST_EQUAL(e.type(), bdecode_node::string_t);
TEST_EQUAL(e.string_value(), std::string("abcdefghijklmnopqrstuvwxyz")); TEST_EQUAL(e.string_value(), std::string("abcdefghijklmnopqrstuvwxyz"));
TEST_EQUAL(e.string_length(), 26); TEST_EQUAL(e.string_length(), 26);
@ -79,11 +79,11 @@ TORRENT_TEST(string_prefix1)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(test.c_str(), test.c_str() + test.size(), e, 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::printf("%d bytes string\n", e.string_length());
std::pair<const char*, int> section = e.data_section(); span<const char> section = e.data_section();
TEST_CHECK(std::memcmp(test.c_str(), section.first, section.second) == 0); TEST_CHECK(std::memcmp(test.c_str(), section.data(), section.size()) == 0);
TEST_EQUAL(section.second, int(test.size())); TEST_EQUAL(section.size(), test.size());
TEST_EQUAL(e.type(), bdecode_node::string_t); TEST_EQUAL(e.type(), bdecode_node::string_t);
TEST_EQUAL(e.string_length(), 1000000); TEST_EQUAL(e.string_length(), 1000000);
TEST_EQUAL(e.string_ptr(), test.c_str() + 8); TEST_EQUAL(e.string_ptr(), test.c_str() + 8);
@ -96,21 +96,21 @@ TORRENT_TEST(list)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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::printf("%s\n", print_entry(e).c_str());
std::pair<const char*, int> section = e.data_section(); span<const char> section = e.data_section();
TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0);
TEST_CHECK(section.second == sizeof(b) - 1); TEST_EQUAL(section.size(), sizeof(b) - 1);
TEST_CHECK(e.type() == bdecode_node::list_t); TEST_EQUAL(e.type(), bdecode_node::list_t);
TEST_CHECK(e.list_size() == 2); TEST_EQUAL(e.list_size(), 2);
TEST_CHECK(e.list_at(0).type() == bdecode_node::int_t); TEST_EQUAL(e.list_at(0).type(), bdecode_node::int_t);
TEST_CHECK(e.list_at(1).type() == bdecode_node::string_t); TEST_EQUAL(e.list_at(1).type(), bdecode_node::string_t);
TEST_CHECK(e.list_at(0).int_value() == 12453); TEST_EQUAL(e.list_at(0).int_value(), 12453);
TEST_CHECK(e.list_at(1).string_value() == std::string("aaa")); TEST_EQUAL(e.list_at(1).string_value(), std::string("aaa"));
TEST_CHECK(e.list_at(1).string_length() == 3); TEST_EQUAL(e.list_at(1).string_length(), 3);
section = e.list_at(1).data_section(); section = e.list_at(1).data_section();
TEST_CHECK(std::memcmp("3:aaa", section.first, section.second) == 0); TEST_CHECK(std::memcmp("3:aaa", section.data(), section.size()) == 0);
TEST_CHECK(section.second == 5); TEST_EQUAL(section.size(), 5);
} }
// test dict // test dict
@ -122,20 +122,20 @@ TORRENT_TEST(dict)
int ret = bdecode(b, b + sizeof(b)-1, e, ec); int ret = bdecode(b, b + sizeof(b)-1, e, ec);
TEST_EQUAL(ret, 0); TEST_EQUAL(ret, 0);
std::printf("%s\n", print_entry(e).c_str()); std::printf("%s\n", print_entry(e).c_str());
std::pair<const char*, int> section = e.data_section(); span<const char> section = e.data_section();
TEST_CHECK(std::memcmp(b, section.first, section.second) == 0); TEST_CHECK(std::memcmp(b, section.data(), section.size()) == 0);
TEST_CHECK(section.second == sizeof(b) - 1); TEST_EQUAL(section.size(), sizeof(b) - 1);
TEST_CHECK(e.type() == bdecode_node::dict_t); TEST_EQUAL(e.type(), bdecode_node::dict_t);
TEST_CHECK(e.dict_size() == 4); TEST_EQUAL(e.dict_size(), 4);
TEST_CHECK(e.dict_find("a").type() == bdecode_node::int_t); TEST_EQUAL(e.dict_find("a").type(), bdecode_node::int_t);
TEST_CHECK(e.dict_find("a").int_value() == 12453); TEST_EQUAL(e.dict_find("a").int_value(), 12453);
TEST_CHECK(e.dict_find("b").type() == bdecode_node::string_t); TEST_EQUAL(e.dict_find("b").type(), bdecode_node::string_t);
TEST_CHECK(e.dict_find("b").string_value() == std::string("aaa")); TEST_EQUAL(e.dict_find("b").string_value(), std::string("aaa"));
TEST_CHECK(e.dict_find("b").string_length() == 3); TEST_EQUAL(e.dict_find("b").string_length(), 3);
TEST_CHECK(e.dict_find("c").type() == bdecode_node::string_t); TEST_EQUAL(e.dict_find("c").type(), bdecode_node::string_t);
TEST_CHECK(e.dict_find("c").string_value() == std::string("bbb")); TEST_EQUAL(e.dict_find("c").string_value(), std::string("bbb"));
TEST_CHECK(e.dict_find("c").string_length() == 3); TEST_EQUAL(e.dict_find("c").string_length(), 3);
TEST_CHECK(e.dict_find_string_value("X") == "0123456789"); TEST_EQUAL(e.dict_find_string_value("X"), "0123456789");
} }
// test dictionary with a key without a value // test dictionary with a key without a value
@ -173,7 +173,7 @@ TORRENT_TEST(dict_null_key)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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); TEST_CHECK(e.dict_size() == 1);
bdecode_node d = e.dict_find(std::string("a\0b", 3)); bdecode_node d = e.dict_find(std::string("a\0b", 3));
TEST_EQUAL(d.type(), bdecode_node::int_t); TEST_EQUAL(d.type(), bdecode_node::int_t);
@ -350,7 +350,7 @@ TORRENT_TEST(64bit_int)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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::printf("%s\n", print_entry(e).c_str());
TEST_CHECK(e.int_value() == 9223372036854775807LL); TEST_CHECK(e.int_value() == 9223372036854775807LL);
} }
@ -362,7 +362,7 @@ TORRENT_TEST(64bit_int_negative)
bdecode_node e; bdecode_node e;
error_code ec; error_code ec;
int ret = bdecode(b, b + sizeof(b)-1, e, 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::printf("%s\n", print_entry(e).c_str());
TEST_CHECK(e.int_value() == -9223372036854775807LL); TEST_CHECK(e.int_value() == -9223372036854775807LL);
} }

View File

@ -70,11 +70,21 @@ sha1_hash to_hash(char const* s)
return ret; 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" 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) 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) msg_args& port(int p)
{ a["port"] = p; return *this; } { a["port"] = p; return *this; }
msg_args& target(char const* t) msg_args& target(sha1_hash const& t)
{ if (t) a["target"] = std::string(t, 20); return *this; } { a["target"] = t.to_string(); return *this; }
msg_args& value(entry const& v) msg_args& value(entry const& v)
{ a["v"] = v; return *this; } { a["v"] = v; return *this; }
@ -175,23 +185,23 @@ struct msg_args
msg_args& seed(bool s) msg_args& seed(bool s)
{ a["seed"] = s ? 1 : 0; return *this; } { a["seed"] = s ? 1 : 0; return *this; }
msg_args& key(std::string k) msg_args& key(public_key const& k)
{ a["k"] = k; return *this; } { a["k"] = k.bytes; return *this; }
msg_args& sig(std::string s) msg_args& sig(signature const& s)
{ a["sig"] = s; return *this; } { a["sig"] = s.bytes; return *this; }
msg_args& seq(int s) msg_args& seq(sequence_number s)
{ a["seq"] = s; return *this; } { a["seq"] = s.value; return *this; }
msg_args& cas(std::int64_t c) msg_args& cas(sequence_number c)
{ a["cas"] = c; return *this; } { a["cas"] = c.value; return *this; }
msg_args& nid(sha1_hash const& n) msg_args& nid(sha1_hash const& n)
{ a["id"] = n.to_string(); return *this; } { a["id"] = n.to_string(); return *this; }
msg_args& salt(char const* s) msg_args& salt(span<char const> s)
{ if (s) a["salt"] = s; return *this; } { if (!s.empty()) a["salt"] = s; return *this; }
msg_args& want(std::string w) msg_args& want(std::string w)
{ a["want"].list().push_back(w); return *this; } { 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; if ((i % items[j].num_peers) == 0) continue;
bdecode_node response; bdecode_node response;
send_dht_request(node, "get", eps[i], &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[] = 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 send_dht_request(node, "put", eps[i], &response
, msg_args() , msg_args()
.token(token) .token(token)
.target((char const*)&items[j].target[0]) .target(items[j].target)
.value(items[j].ent)); .value(items[j].ent));
key_desc_t const desc2[] = key_desc_t const desc2[] =
@ -385,7 +395,7 @@ void announce_immutable_items(node& node, udp::endpoint const* eps
{ {
bdecode_node response; bdecode_node response;
send_dht_request(node, "get", eps[j], &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[] = 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}, {"a", bdecode_node::dict_t, 0, key_desc_t::parse_children},
{"id", bdecode_node::string_t, 20, 0}, {"id", bdecode_node::string_t, 20, 0},
{"cas", bdecode_node::string_t, 20, key_desc_t::optional}, {"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}, {"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}, {"token", bdecode_node::string_t, 2, 0},
{"v", bdecode_node::none_t, 0, key_desc_t::last_child}, {"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; nid[0] = 0x18;
int nodes_num = std::get<0>(t.dht_node.size()); int nodes_num = std::get<0>(t.dht_node.size());
send_dht_request(t.dht_node, "find_node", t.source, &response 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]; bdecode_node err_keys[2];
bool ret = dht::verify_message(response, err_desc, err_keys, t.error_string 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 else
nid[0] = 0x0a; nid[0] = 0x0a;
send_dht_request(t.dht_node, "find_node", t.source, &response 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[] = { dht::key_desc_t const nodes_desc[] = {
{"y", bdecode_node::string_t, 1, 0}, {"y", bdecode_node::string_t, 1, 0},
@ -981,7 +995,7 @@ namespace {
return nodes; return nodes;
} }
std::pair<char const*, int> const empty_salt(nullptr, 0); span<char const> const empty_salt;
} }
// TODO: 3 split this up into smaller tests // TODO: 3 split this up into smaller tests
@ -1018,41 +1032,42 @@ void test_put(address(&rand_addr)())
// ==== get / put mutable items === // ==== get / put mutable items ===
std::pair<char const*, int> itemv; span<char const> itemv;
char signature[item_sig_len]; signature sig;
char buffer[1200]; char buffer[1200];
int seq = 4; sequence_number seq(4);
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); 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) 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" std::fprintf(stderr, "\nTEST GET/PUT%s \ngenerating ed25519 keys\n\n"
, with_salt ? " with-salt" : " no-salt"); , with_salt ? " with-salt" : " no-salt");
unsigned char seed[32]; unsigned char seed[32];
ed25519_create_seed(seed); 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" 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(pk.bytes.data(), public_key::len)).c_str()
, aux::to_hex(std::string(private_key, item_sk_len)).c_str()); , aux::to_hex(std::string(sk.bytes.data(), secret_key::len)).c_str());
std::pair<const char*, int> salt(nullptr, 0); std::string salt;
if (with_salt) if (with_salt) salt = "foobar";
salt = std::pair<char const*, int>("foobar", 6);
hasher h(public_key, 32); hasher h(pk.bytes);
if (with_salt) h.update(salt.first, salt.second); if (with_salt) h.update(salt);
sha1_hash target_id = h.final(); sha1_hash target_id = h.final();
std::fprintf(stderr, "target_id: %s\n" std::fprintf(stderr, "target_id: %s\n"
, aux::to_hex(target_id.to_string()).c_str()); , aux::to_hex(target_id.to_string()).c_str());
send_dht_request(t.dht_node, "get", t.source, &response 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[] = key_desc_t const desc[] =
{ {
@ -1084,18 +1099,18 @@ void test_put(address(&rand_addr)())
TEST_ERROR(t.error_string); TEST_ERROR(t.error_string);
} }
itemv = std::pair<char const*, int>(buffer, bencode(buffer, items[0].ent)); itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); sign_mutable_item(itemv, salt, seq, pk, sk, sig);
TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), true); TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), true);
send_dht_request(t.dht_node, "put", t.source, &response send_dht_request(t.dht_node, "put", t.source, &response
, msg_args() , msg_args()
.token(token) .token(token)
.value(items[0].ent) .value(items[0].ent)
.key(std::string(public_key, item_pk_len)) .key(pk)
.sig(std::string(signature, item_sig_len)) .sig(sig)
.seq(seq) .seq(seq)
.salt(salt.first)); .salt(salt));
ret = verify_message(response, desc2, desc2_keys, t.error_string ret = verify_message(response, desc2, desc2_keys, t.error_string
, sizeof(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 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" std::fprintf(stderr, "target_id: %s\n"
, aux::to_hex(target_id.to_string()).c_str()); , aux::to_hex(target_id.to_string()).c_str());
@ -1146,33 +1161,33 @@ void test_put(address(&rand_addr)())
, print_entry(response).c_str()); , print_entry(response).c_str());
char value[1020]; char value[1020];
char* ptr = value; char* ptr = value;
int value_len = bencode(ptr, items[0].ent); int const value_len = bencode(ptr, items[0].ent);
TEST_EQUAL(value_len, desc3_keys[2].data_section().second); TEST_EQUAL(value_len, int(desc3_keys[2].data_section().size()));
TEST_CHECK(memcmp(desc3_keys[2].data_section().first, value, value_len) == 0); 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! // also test that invalid signatures fail!
itemv = std::pair<char const*, int>(buffer, bencode(buffer, items[0].ent)); itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); sign_mutable_item(itemv, salt, seq, pk, sk, sig);
TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), 1); TEST_EQUAL(verify_mutable_item(itemv, salt, seq, pk, sig), 1);
// break the signature // break the signature
signature[2] ^= 0xaa; sig.bytes[2] ^= 0xaa;
std::fprintf(stderr, "PUT broken signature\n"); 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 send_dht_request(t.dht_node, "put", t.source, &response
, msg_args() , msg_args()
.token(token) .token(token)
.value(items[0].ent) .value(items[0].ent)
.key(std::string(public_key, item_pk_len)) .key(pk)
.sig(std::string(signature, item_sig_len)) .sig(sig)
.seq(seq) .seq(seq)
.salt(salt.first)); .salt(salt));
ret = verify_message(response, desc_error, desc_error_keys, t.error_string ret = verify_message(response, desc_error, desc_error_keys, t.error_string
, sizeof(t.error_string)); , sizeof(t.error_string));
@ -1193,7 +1208,7 @@ void test_put(address(&rand_addr)())
// === test conditional get === // === test conditional get ===
send_dht_request(t.dht_node, "get", t.source, &response 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"); 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 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"); bdecode_node r = response.dict_find_dict("r");
@ -1215,16 +1230,16 @@ void test_put(address(&rand_addr)())
// === test CAS put === // === test CAS put ===
// this is the sequence number we expect to be there // this is the sequence number we expect to be there
std::uint64_t cas = seq; sequence_number cas = seq;
// increment sequence number // increment sequence number
++seq; seq = next_seq(seq);
// put item 1 // put item 1
itemv = std::pair<char const*, int>(buffer, bencode(buffer, items[1].ent)); itemv = span<char const>(buffer, bencode(buffer, items[1].ent));
sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); sign_mutable_item(itemv, salt, seq, pk, sk, sig);
TEST_EQUAL(verify_mutable_item(itemv, salt, seq, public_key, signature), 1); 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"); std::fprintf(stderr, "PUT CAS 1\n");
@ -1232,11 +1247,11 @@ void test_put(address(&rand_addr)())
, msg_args() , msg_args()
.token(token) .token(token)
.value(items[1].ent) .value(items[1].ent)
.key(std::string(public_key, item_pk_len)) .key(pk)
.sig(std::string(signature, item_sig_len)) .sig(sig)
.seq(seq) .seq(seq)
.cas(cas) .cas(cas)
.salt(salt.first)); .salt(salt));
ret = verify_message(response, desc2, desc2_keys, t.error_string ret = verify_message(response, desc2, desc2_keys, t.error_string
, sizeof(t.error_string)); , sizeof(t.error_string));
@ -1262,11 +1277,11 @@ void test_put(address(&rand_addr)())
, msg_args() , msg_args()
.token(token) .token(token)
.value(items[1].ent) .value(items[1].ent)
.key(std::string(public_key, item_pk_len)) .key(pk)
.sig(std::string(signature, item_sig_len)) .sig(sig)
.seq(seq) .seq(seq)
.cas(cas) .cas(cas)
.salt(salt.first)); .salt(salt));
ret = verify_message(response, desc_error, desc_error_keys, t.error_string ret = verify_message(response, desc_error, desc_error_keys, t.error_string
, sizeof(t.error_string)); , sizeof(t.error_string));
@ -1767,23 +1782,22 @@ TORRENT_TEST(get_peers_v6)
} }
#endif #endif
// TODO: 4 pass in th actual salt as the argument
void test_mutable_get(address(&rand_addr)(), bool const with_salt) void test_mutable_get(address(&rand_addr)(), bool const with_salt)
{ {
dht_test_setup t(udp::endpoint(rand_addr(), 20)); dht_test_setup t(udp::endpoint(rand_addr(), 20));
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); get_test_keypair(pk, sk);
char signature[item_sig_len];
char buffer[1200]; char buffer[1200];
int seq = 4; sequence_number seq(4);
std::pair<char const*, int> itemv; span<char const> itemv;
bdecode_node response; bdecode_node response;
std::pair<const char*, int> salt(nullptr, 0); std::string salt;
if (with_salt) if (with_salt) salt = "foobar";
salt = std::pair<char const*, int>("foobar", 6);
// mutable get // 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); udp::endpoint const initial_node(rand_addr(), 1234);
t.dht_node.m_table.add_node(initial_node); t.dht_node.m_table.add_node(initial_node);
g_put_item.assign(items[0].ent, salt, seq, public_key, private_key); g_put_item.assign(items[0].ent, salt, seq, pk, sk);
std::string sig(g_put_item.sig().data(), item_sig_len); t.dht_node.put_item(pk, std::string()
t.dht_node.put_item(public_key, std::string()
, std::bind(&put_mutable_item_cb, _1, _2, 0) , std::bind(&put_mutable_item_cb, _1, _2, 0)
, put_mutable_item_data_cb); , put_mutable_item_data_cb);
@ -1804,7 +1817,7 @@ void test_mutable_get(address(&rand_addr)(), bool const with_salt)
g_sent_packets.clear(); 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); TEST_EQUAL(g_sent_packets.size(), 1);
if (g_sent_packets.empty()) return; 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(); g_sent_packets.clear();
itemv = std::pair<char const*, int>(buffer, bencode(buffer, items[0].ent)); signature sig;
sign_mutable_item(itemv, salt, seq, public_key, private_key, signature); itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
sign_mutable_item(itemv, salt, seq, pk, sk, sig);
send_dht_response(t.dht_node, response, initial_node send_dht_response(t.dht_node, response, initial_node
, msg_args() , msg_args()
.token("10") .token("10")
.port(1234) .port(1234)
.value(items[0].ent) .value(items[0].ent)
.key(std::string(public_key, item_pk_len)) .key(pk)
.sig(std::string(signature, item_sig_len)) .sig(sig)
.salt(salt.first) .salt(salt)
.seq(seq)); .seq(seq));
TEST_CHECK(g_sent_packets.empty()); 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; if (g_got_items.empty()) return;
TEST_EQUAL(g_got_items.front().value(), items[0].ent); 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(g_got_items.front().pk() == pk);
TEST_CHECK(memcmp(g_got_items.front().sig().data(), signature, item_sig_len) == 0); TEST_CHECK(g_got_items.front().sig() == sig);
TEST_EQUAL(int(g_got_items.front().seq()), seq); TEST_CHECK(g_got_items.front().seq() == seq);
g_got_items.clear(); g_got_items.clear();
} }
@ -1929,7 +1943,7 @@ TORRENT_TEST(immutable_get)
TORRENT_TEST(immutable_put) TORRENT_TEST(immutable_put)
{ {
bdecode_node response; bdecode_node response;
std::pair<char const*, int> itemv; span<char const> itemv;
char buffer[1200]; char buffer[1200];
dht::key_desc_t const put_immutable_item_desc[] = { dht::key_desc_t const put_immutable_item_desc[] = {
@ -1963,7 +1977,7 @@ TORRENT_TEST(immutable_put)
std::string flat_data; std::string flat_data;
bencode(std::back_inserter(flat_data), put_data); bencode(std::back_inserter(flat_data), put_data);
sha1_hash target = item_target_id( sha1_hash target = item_target_id(
std::pair<char const*, int>(flat_data.c_str(), int(flat_data.size()))); span<char const>(flat_data.c_str(), int(flat_data.size())));
t.dht_node.put_item(target, put_data, std::bind(&put_immutable_item_cb, _1, loop)); 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); TEST_EQUAL(g_sent_packets.size(), 8);
if (g_sent_packets.size() != 8) break; if (g_sent_packets.size() != 8) break;
itemv = std::pair<char const*, int>(buffer, bencode(buffer, put_data)); itemv = span<char const>(buffer, bencode(buffer, put_data));
for (int i = 0; i < 8; ++i) 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[0].string_value(), "q");
TEST_EQUAL(put_immutable_item_keys[2].string_value(), "put"); TEST_EQUAL(put_immutable_item_keys[2].string_value(), "put");
std::pair<const char*, int> v = put_immutable_item_keys[6].data_section(); span<const char> v = put_immutable_item_keys[6].data_section();
TEST_EQUAL(std::string(v.first, v.second), flat_data); TEST_EQUAL(std::string(v.data(), v.size()), flat_data);
char tok[10]; char tok[10];
std::snprintf(tok, sizeof(tok), "%02d", i); std::snprintf(tok, sizeof(tok), "%02d", i);
TEST_EQUAL(put_immutable_item_keys[5].string_value(), tok); TEST_EQUAL(put_immutable_item_keys[5].string_value(), tok);
@ -2039,14 +2053,14 @@ TORRENT_TEST(immutable_put)
TORRENT_TEST(mutable_put) TORRENT_TEST(mutable_put)
{ {
bdecode_node response; bdecode_node response;
std::pair<char const*, int> itemv; span<char const> itemv;
char buffer[1200]; char buffer[1200];
bdecode_node put_mutable_item_keys[11]; bdecode_node put_mutable_item_keys[11];
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); get_test_keypair(pk, sk);
int seq = 4; sequence_number seq(4);
// mutable put // mutable put
g_sent_packets.clear(); g_sent_packets.clear();
@ -2063,9 +2077,9 @@ TORRENT_TEST(mutable_put)
for (int i = 0; i < num_test_nodes; ++i) for (int i = 0; i < num_test_nodes; ++i)
t.dht_node.m_table.add_node(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); g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk);
std::string sig(g_put_item.sig().data(), item_sig_len); signature const sig = g_put_item.sig();
t.dht_node.put_item(public_key, std::string() t.dht_node.put_item(pk, std::string()
, std::bind(&put_mutable_item_cb, _1, _2, loop) , std::bind(&put_mutable_item_cb, _1, _2, loop)
, put_mutable_item_data_cb); , put_mutable_item_data_cb);
@ -2100,7 +2114,7 @@ TORRENT_TEST(mutable_put)
TEST_EQUAL(g_sent_packets.size(), 8); TEST_EQUAL(g_sent_packets.size(), 8);
if (g_sent_packets.size() != 8) break; if (g_sent_packets.size() != 8) break;
itemv = std::pair<char const*, int>(buffer, bencode(buffer, items[0].ent)); itemv = span<char const>(buffer, bencode(buffer, items[0].ent));
for (int i = 0; i < 8; ++i) 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[0].string_value(), "q");
TEST_EQUAL(put_mutable_item_keys[2].string_value(), "put"); 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[6].string_value(), std::string(pk.bytes.data(), public_key::len));
TEST_EQUAL(put_mutable_item_keys[7].int_value(), seq); TEST_EQUAL(put_mutable_item_keys[7].int_value(), int(seq.value));
TEST_EQUAL(put_mutable_item_keys[8].string_value(), sig); TEST_EQUAL(put_mutable_item_keys[8].string_value(), std::string(sig.bytes.data(), signature::len));
std::pair<const char*, int> v = put_mutable_item_keys[10].data_section(); span<const char> v = put_mutable_item_keys[10].data_section();
TEST_EQUAL(v.second, itemv.second); TEST_EQUAL(v.size(), itemv.size());
TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0); TEST_CHECK(memcmp(v.data(), itemv.data(), itemv.size()) == 0);
char tok[10]; char tok[10];
std::snprintf(tok, sizeof(tok), "%02d", i); std::snprintf(tok, sizeof(tok), "%02d", i);
TEST_EQUAL(put_mutable_item_keys[9].string_value(), tok); 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 // set the branching factor to k to make this a little easier
t.sett.search_branching = 8; t.sett.search_branching = 8;
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); get_test_keypair(pk, sk);
int seq = 4; sequence_number seq(4);
bdecode_node response; bdecode_node response;
// verify that done() is only invoked once // verify that done() is only invoked once
// See PR 252 // See PR 252
g_sent_packets.clear(); 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 enum { num_test_nodes = 9 }; // we need K + 1 nodes to create the failing sequence
std::array<node_entry, 9> nodes = build_nodes(target); std::array<node_entry, 9> nodes = build_nodes(target);
@ -2175,8 +2189,8 @@ TORRENT_TEST(traversal_done)
t.dht_node.m_table.add_node(nodes[i]); t.dht_node.m_table.add_node(nodes[i]);
// kick off a mutable put request // kick off a mutable put request
g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key); g_put_item.assign(items[0].ent, empty_salt, seq, pk, sk);
t.dht_node.put_item(public_key, std::string() t.dht_node.put_item(pk, std::string()
, std::bind(&put_mutable_item_cb, _1, _2, 0) , std::bind(&put_mutable_item_cb, _1, _2, 0)
, put_mutable_item_data_cb); , put_mutable_item_data_cb);
TEST_EQUAL(g_sent_packets.size(), 8); 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); udp::endpoint source(addr("10.0.0.1"), 20);
send_dht_request(node4, "find_node", source, &response 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[] = { dht::key_desc_t const nodes6_desc[] = {
{ "y", bdecode_node::string_t, 1, 0 }, { "y", bdecode_node::string_t, 1, 0 },
@ -2366,50 +2382,47 @@ TORRENT_TEST(signing_test1)
// test vector 1 // test vector 1
// test content // test content
std::pair<char const*, int> test_content("12:Hello World!", 15); span<char const> test_content("12:Hello World!", 15);
// test salt // test salt
std::pair<char const*, int> test_salt("foobar", 6); span<char const> test_salt("foobar", 6);
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); get_test_keypair(pk, sk);
std::pair<char const*, int> empty_salt; span<char const> 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 TEST_EQUAL(aux::to_hex(std::string(sig.bytes.data(), signature::len))
, private_key, signature);
TEST_EQUAL(aux::to_hex(std::string(signature, 64))
, "305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff" , "305ac8aeb6c9c151fa120f120ea2cfb923564e11552d06a5d856091e5e853cff"
"1260d3f39e4999684aa92eb73ffd136e6f4f3ecbfda0ce53a1608ecd7ae21f01"); "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"); TEST_EQUAL(aux::to_hex(target_id.to_string()), "4a533d47ec9c7d95b1ad75f576cffc641853b750");
} }
TORRENT_TEST(signing_test2) TORRENT_TEST(signing_test2)
{ {
char public_key[item_pk_len]; public_key pk;
char private_key[item_sk_len]; secret_key sk;
get_test_keypair(public_key, private_key); get_test_keypair(pk, sk);
// test content // test content
std::pair<char const*, int> test_content("12:Hello World!", 15); span<char const> test_content("12:Hello World!", 15);
char signature[item_sig_len]; signature sig;
// test salt // test salt
std::pair<char const*, int> test_salt("foobar", 6); span<char const> test_salt("foobar", 6);
// test vector 2 (the keypair is the same as test 1) // test vector 2 (the keypair is the same as test 1)
sign_mutable_item(test_content, test_salt, 1, public_key sign_mutable_item(test_content, test_salt, sequence_number(1), pk, sk, sig);
, private_key, signature);
TEST_EQUAL(aux::to_hex(std::string(signature, 64)) TEST_EQUAL(aux::to_hex(std::string(sig.bytes.data(), signature::len))
, "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d" , "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17d"
"df9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"); "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"); TEST_EQUAL(aux::to_hex(target_id.to_string()), "411eba73b6f087ca51a3795d9c8c938d365e32c1");
} }
@ -2418,7 +2431,7 @@ TORRENT_TEST(signing_test3)
// test vector 3 // test vector 3
// test content // test content
std::pair<char const*, int> test_content("12:Hello World!", 15); span<char const> test_content("12:Hello World!", 15);
sha1_hash target_id = item_target_id(test_content); sha1_hash target_id = item_target_id(test_content);
TEST_EQUAL(aux::to_hex(target_id.to_string()), "e5f96f6f38320f0f33959cb4d3d656452117aadb"); 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); send_dht_request(node, "ping", source, &response, args, "10", false);
TEST_EQUAL(response.type(), bdecode_node::none_t); 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); send_dht_request(node, "get", source, &response, args, "10", false);
TEST_EQUAL(response.type(), bdecode_node::none_t); TEST_EQUAL(response.type(), bdecode_node::none_t);

View File

@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/session.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/bencode.hpp"
#include "libtorrent/socket_io.hpp" // for hash_address #include "libtorrent/socket_io.hpp" // for hash_address
#include "libtorrent/broadcast_socket.hpp" // for supports_ipv6 #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); bool r = s->get_immutable_item(n4, item);
TEST_CHECK(!r); 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); r = s->get_immutable_item(n4, item);
TEST_CHECK(r); TEST_CHECK(r);
s->put_immutable_item(n1, "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, address::from_string("124.31.75.21")); s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21"));
r = s->get_immutable_item(n1, item); r = s->get_immutable_item(n1, item);
TEST_CHECK(!r); 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); TEST_CHECK(!r);
char public_key[item_pk_len]; public_key pk;
char signature[item_sig_len]; signature sig;
s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk
r = s->get_mutable_item(n4, 0, false, item); , {"salt", 4}, addr("124.31.75.21"));
r = s->get_mutable_item(n4, sequence_number(0), false, item);
TEST_CHECK(r); TEST_CHECK(r);
} }
@ -188,17 +189,18 @@ TORRENT_TEST(counters)
entry item; 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); 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(n1, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21"));
TEST_EQUAL(s->counters().immutable_data, 2); TEST_EQUAL(s->counters().immutable_data, 2);
char public_key[item_pk_len]; public_key pk;
char signature[item_sig_len]; signature sig;
s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); 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); TEST_EQUAL(s->counters().mutable_data, 1);
} }
@ -286,7 +288,7 @@ TORRENT_TEST(immutable_item_limit)
for (int i = 0; i < 200; ++i) 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(); dht_storage_counters cnt = s->counters();
TEST_CHECK(cnt.immutable_data <= 42); TEST_CHECK(cnt.immutable_data <= 42);
} }
@ -300,11 +302,12 @@ TORRENT_TEST(mutable_item_limit)
sett.max_dht_items = 42; sett.max_dht_items = 42;
std::unique_ptr<dht_storage_interface> s(create_default_dht_storage(sett)); std::unique_ptr<dht_storage_interface> s(create_default_dht_storage(sett));
char public_key[item_pk_len]; public_key pk;
char signature[item_sig_len]; signature sig;
for (int i = 0; i < 200; ++i) 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(); dht_storage_counters cnt = s->counters();
TEST_CHECK(cnt.mutable_data <= 42); TEST_CHECK(cnt.mutable_data <= 42);
} }
@ -342,15 +345,15 @@ TORRENT_TEST(update_node_ids)
// all items will have one announcer, all calculations // all items will have one announcer, all calculations
// for item erase will be reduced to the distance // 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(); cnt = s->counters();
TEST_EQUAL(cnt.immutable_data, 1); 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(); cnt = s->counters();
TEST_EQUAL(cnt.immutable_data, 2); TEST_EQUAL(cnt.immutable_data, 2);
// at this point, the least important (h2) will removed // at this point, the least important (h2) will removed
// to make room for h3 // 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(); cnt = s->counters();
TEST_EQUAL(cnt.immutable_data, 2); TEST_EQUAL(cnt.immutable_data, 2);

View File

@ -69,8 +69,8 @@ dht_direct_response_alert* get_direct_response(lt::session& ses)
{ {
for (;;) for (;;)
{ {
alert* a = ses.wait_for_alert(seconds(20)); alert* a = ses.wait_for_alert(seconds(30));
// it shouldn't take more than 20 seconds to get a response // 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 // so fail the test and bail out if we don't get an alert in that time
TEST_CHECK(a); TEST_CHECK(a);
if (!a) return nullptr; if (!a) return nullptr;

View File

@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" // for bencode() #include "libtorrent/bencode.hpp" // for bencode()
#include "libtorrent/kademlia/item.hpp" // for sign_mutable_item #include "libtorrent/kademlia/item.hpp" // for sign_mutable_item
#include "libtorrent/ed25519.hpp" #include "libtorrent/ed25519.hpp"
#include "libtorrent/span.hpp"
#include <functional> #include <functional>
#include <cstdio> // for snprintf #include <cstdio> // for snprintf
@ -112,8 +113,11 @@ alert* wait_for_alert(lt::session& s, int alert_type)
return ret; return ret;
} }
void put_string(entry& e, std::array<char, 64>& sig, std::uint64_t& seq void put_string(entry& e, std::array<char, 64>& sig
, std::string const& salt, char const* public_key, char const* private_key , std::uint64_t& seq
, std::string const& salt
, std::array<char, 32> const& pk
, std::array<char, 64> const& sk
, char const* str) , char const* str)
{ {
using libtorrent::dht::sign_mutable_item; using libtorrent::dht::sign_mutable_item;
@ -121,13 +125,12 @@ void put_string(entry& e, std::array<char, 64>& sig, std::uint64_t& seq
e = std::string(str); e = std::string(str);
std::vector<char> buf; std::vector<char> buf;
bencode(std::back_inserter(buf), e); bencode(std::back_inserter(buf), e);
dht::signature sign;
++seq; ++seq;
sign_mutable_item(std::pair<char const*, int>(&buf[0], int(buf.size())) sign_mutable_item(buf, salt, dht::sequence_number(seq)
, std::pair<char const*, int>(&salt[0], int(salt.size())) , dht::public_key(pk.data())
, seq , dht::secret_key(sk.data()), sign);
, public_key sig = sign.bytes;
, private_key
, sig.data());
} }
void bootstrap(lt::session& s) void bootstrap(lt::session& s)
@ -156,14 +159,14 @@ int dump_key(char *filename)
} }
std::fclose(f); std::fclose(f);
std::array<char, 32> public_key; std::array<char, 32> pk;
std::array<char, 64> private_key; std::array<char, 64> sk;
ed25519_create_keypair((unsigned char*)public_key.data() ed25519_create_keypair((unsigned char*)pk.data()
, (unsigned char*)private_key.data(), seed); , (unsigned char*)sk.data(), seed);
std::printf("public key: %s\nprivate key: %s\n", 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(pk.data(), pk.size())).c_str()
to_hex(std::string(private_key.data(), private_key.size())).c_str()); , to_hex(std::string(sk.data(), sk.size())).c_str());
return 0; return 0;
} }
@ -359,7 +362,7 @@ int main(int argc, char* argv[])
bootstrap(s); bootstrap(s);
s.dht_put_item(public_key, std::bind(&put_string, _1, _2, _3, _4 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() std::printf("MPUT publick key: %s\n", to_hex(std::string(public_key.data()
, public_key.size())).c_str()); , public_key.size())).c_str());