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 ;
# disable warning C4275: non DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier'
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) ;

View File

@ -457,9 +457,9 @@ namespace
ses.dht_get_item(public_key, salt);
}
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 data)
void put_string(entry& e, std::array<char, 64>& sig, std::uint64_t& seq
, std::string const& salt, std::string pk, std::string sk
, std::string data)
{
using libtorrent::dht::sign_mutable_item;
@ -467,21 +467,25 @@ namespace
std::vector<char> buf;
bencode(std::back_inserter(buf), e);
++seq;
sign_mutable_item(std::pair<char const*, int>(&buf[0], int(buf.size()))
, std::pair<char const*, int>(&salt[0], int(salt.size()))
, seq, public_key.c_str(), private_key.c_str(), sig.data());
dht::signature sign;
sign_mutable_item(buf, salt
, dht::sequence_number(seq)
, dht::public_key(pk.data())
, dht::secret_key(sk.data())
, sign);
sig = sign.bytes;
}
void dht_put_mutable_item(lt::session& ses, std::string private_key, std::string public_key,
std::string data, std::string salt)
std::string data, std::string salt)
{
TORRENT_ASSERT(private_key.size() == 64);
TORRENT_ASSERT(public_key.size() == 32);
std::array<char, 32> key;
std::copy(public_key.begin(), public_key.end(), key.begin());
ses.dht_put_item(key, boost::bind(&put_string, _1, _2, _3, _4
, public_key, private_key, data)
, salt);
, public_key, private_key, data)
, salt);
}
#endif

View File

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

View File

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

View File

@ -20,6 +20,8 @@ extern "C" {
void TORRENT_EXPORT ed25519_create_seed(unsigned char *seed);
#endif
// TODO: 3 wrap these into C++ calls with proper types (dht::signature,
// public_key and secret_key)
void TORRENT_EXPORT ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed);
void TORRENT_EXPORT ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key);
int TORRENT_EXPORT ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *private_key);

View File

@ -49,6 +49,7 @@ namespace libtorrent
namespace aux {
TORRENT_EXTRA_EXPORT int hex_to_int(char in);
// TODO: 3 take an span here instead
TORRENT_EXTRA_EXPORT bool is_hex(char const *in, int len);
// The overload taking a ``std::string`` converts (binary) the string ``s``
@ -58,6 +59,7 @@ namespace libtorrent
// ``out``. The caller is responsible for making sure the buffer pointed to
// by ``out`` is large enough, i.e. has at least len * 2 bytes of space.
TORRENT_DEPRECATED_EXPORT std::string to_hex(std::string const& s);
// TODO: 3 take an span here instead
TORRENT_DEPRECATED_EXPORT void to_hex(char const *in, int len, char* out);
// converts the buffer [``in``, ``in`` + len) from hexadecimal to
@ -65,6 +67,7 @@ namespace libtorrent
// by ``out``. The caller is responsible for making sure the buffer
// at ``out`` has enough space for the result to be written to, i.e.
// (len + 1) / 2 bytes.
// TODO: 3 take an span here instead
TORRENT_DEPRECATED_EXPORT bool from_hex(char const *in, int len, char* out);
}

View File

@ -40,10 +40,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/disable_warnings_pop.hpp"
#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/types.hpp>
#include <libtorrent/socket.hpp>
#include <libtorrent/sha1_hash.hpp>
#include <libtorrent/address.hpp>
#include <libtorrent/span.hpp>
namespace libtorrent
{
@ -164,7 +166,7 @@ namespace dht
// dht_settings::max_dht_items.
//
virtual void put_immutable_item(sha1_hash const& target
, char const* buf, int size
, span<char const> buf
, address const& addr) = 0;
// This function retrieves the sequence number of a mutable item.
@ -173,7 +175,7 @@ namespace dht
// inside the out parameter seq.
//
virtual bool get_mutable_item_seq(sha1_hash const& target
, std::int64_t& seq) const = 0;
, sequence_number& seq) const = 0;
// This function retrieves the mutable stored in the DHT.
//
@ -189,7 +191,7 @@ namespace dht
// inside the (entry) out parameter item.
//
virtual bool get_mutable_item(sha1_hash const& target
, std::int64_t seq, bool force_fill
, sequence_number seq, bool force_fill
, entry& item) const = 0;
// Store the item's data. This layer is only for storage.
@ -201,11 +203,11 @@ namespace dht
// dht_settings::max_dht_items.
//
virtual void put_mutable_item(sha1_hash const& target
, char const* buf, int size
, char const* sig
, std::int64_t seq
, char const* pk
, char const* salt, int salt_size
, span<char const> buf
, signature const& sig
, sequence_number seq
, public_key const& pk
, span<char const> salt
, address const& addr) = 0;
// 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.
// the salt is optional
void get_item(char const* key
void get_item(public_key const& key
, boost::function<void(item const&, bool)> cb
, std::string salt = std::string());
@ -119,7 +119,7 @@ namespace libtorrent { namespace dht
// for mutable_item.
// the data_cb will be called when we get authoritative mutable_item,
// the cb is same as put immutable_item.
void put_item(char const* key
void put_item(public_key const& key
, boost::function<void(item const&, int)> cb
, 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;
find_data(node & node, node_id target
find_data(node& node, node_id target
, nodes_callback const& ncallback);
void got_write_token(node_id const& n, std::string const& write_token);

View File

@ -46,9 +46,9 @@ public:
typedef boost::function<void(item const&, bool)> data_callback;
void got_data(bdecode_node const& v,
char const* pk,
std::uint64_t seq,
char const* sig);
public_key const& pk,
sequence_number seq,
signature const& sig);
// for immutable itms
get_item(node& dht_node
@ -58,8 +58,8 @@ public:
// for mutable items
get_item(node& dht_node
, char const* pk
, std::string const& salt
, public_key const& pk
, span<char const> salt
, data_callback const& dcallback
, 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.
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/bdecode.hpp>
#include <libtorrent/entry.hpp>
#include <libtorrent/span.hpp>
#include <libtorrent/kademlia/types.hpp>
#include <vector>
#include <exception>
#include <array>
@ -44,19 +47,18 @@ namespace libtorrent { namespace dht
{
// calculate the target hash for an immutable item.
sha1_hash TORRENT_EXTRA_EXPORT item_target_id(
std::pair<char const*, int> v);
sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span<char const> v);
// calculate the target hash for a mutable item.
sha1_hash TORRENT_EXTRA_EXPORT item_target_id(std::pair<char const*, int> salt
, char const* pk);
sha1_hash TORRENT_EXTRA_EXPORT item_target_id(span<char const> salt
, public_key const& pk);
bool TORRENT_EXTRA_EXPORT verify_mutable_item(
std::pair<char const*, int> v
, std::pair<char const*, int> salt
, std::uint64_t seq
, char const* pk
, char const* sig);
span<char const> v
, span<char const> salt
, sequence_number seq
, public_key const& pk
, signature const& sig);
// TODO: since this is a public function, it should probably be moved
// out of this header and into one with other public functions.
@ -68,47 +70,40 @@ bool TORRENT_EXTRA_EXPORT verify_mutable_item(
// is responsible for allocating the destination buffer that's passed in
// as the ``sig`` argument. Typically it would be allocated on the stack.
void TORRENT_EXPORT sign_mutable_item(
std::pair<char const*, int> v
, std::pair<char const*, int> salt
, std::uint64_t seq
, char const* pk
, char const* sk
, char* sig);
enum
{
item_pk_len = 32,
item_sk_len = 64,
item_sig_len = 64
};
span<char const> v
, span<char const> salt
, sequence_number seq
, public_key const& pk
, secret_key const& sk
, signature& sig);
class TORRENT_EXTRA_EXPORT item
{
public:
item() : m_seq(0), m_mutable(false) {}
item(char const* pk, std::string const& salt);
item(entry const& v) { assign(v); }
item(entry const& v
, std::pair<char const*, int> salt
, std::uint64_t seq, char const* pk, char const* sk);
item(bdecode_node const& v) { assign(v); }
item(public_key const& pk, span<char const> salt);
item(entry v);
item(entry v
, span<char const> salt
, sequence_number seq
, public_key const& pk
, secret_key const& sk);
item(bdecode_node const& v);
void assign(entry const& v)
{
assign(v, std::pair<char const*, int>(static_cast<char const*>(nullptr)
, 0), 0, nullptr, nullptr);
}
void assign(entry const& v, std::pair<char const*, int> salt
, std::uint64_t seq, char const* pk, char const* sk);
void assign(bdecode_node const& v)
{
assign(v, std::pair<char const*, int>(static_cast<char const*>(nullptr)
, 0), 0, nullptr, nullptr);
}
bool assign(bdecode_node const& v, std::pair<char const*, int> salt
, std::uint64_t seq, char const* pk, char const* sig);
void assign(entry const& v, std::string salt, std::uint64_t seq
, char const* pk, char const* sig);
void assign(entry v);
void assign(entry v, span<char const> salt
, sequence_number seq
, public_key const& pk
, secret_key const& sk);
void assign(bdecode_node const& v);
bool assign(bdecode_node const& v, span<char const> salt
, sequence_number seq
, public_key const& pk
, signature const& sig);
void assign(entry v, span<char const> salt
, sequence_number seq
, public_key const& pk
, signature const& sig);
void clear() { m_value = entry(); }
bool empty() const { return m_value.type() == entry::undefined_t; }
@ -116,19 +111,19 @@ public:
bool is_mutable() const { return m_mutable; }
entry const& value() const { return m_value; }
std::array<char, item_pk_len> const& pk() const
public_key const& pk() const
{ return m_pk; }
std::array<char, item_sig_len> const& sig() const
signature const& sig() const
{ return m_sig; }
std::uint64_t seq() const { return m_seq; }
sequence_number seq() const { return m_seq; }
std::string const& salt() const { return m_salt; }
private:
entry m_value;
std::string m_salt;
std::array<char, item_pk_len> m_pk;
std::array<char, item_sig_len> m_sig;
std::uint64_t m_seq;
public_key m_pk;
signature m_sig;
sequence_number m_seq;
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
namespace dht_detail {
//#error move this to its own .hpp/.cpp pair and make it take an span instead of being a template
TORRENT_EXPORT bool verify_message(bdecode_node const& msg, key_desc_t const desc[]
, bdecode_node ret[], int size, char* error, int error_size);

View File

@ -150,17 +150,17 @@ public:
, boost::function<void(msg 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(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&)> data_cb);
bool verify_token(std::string const& token, char const* info_hash
bool verify_token(std::string const& token, sha1_hash const& info_hash
, udp::endpoint const& addr) const;
std::string generate_token(udp::endpoint const& addr, char const* info_hash);
std::string generate_token(udp::endpoint const& addr, sha1_hash const& info_hash);
// the returned time is the delay until connection_timeout()
// should be called again the next time

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

@ -419,7 +419,7 @@ namespace libtorrent
// calling the callback in between is convenient.
void dht_put_item(std::array<char, 32> key
, boost::function<void(entry&, std::array<char,64>&
, std::uint64_t&, std::string const&)> cb
, std::uint64_t&, std::string const&)> cb
, std::string salt = std::string());
void dht_get_peers(sha1_hash const& info_hash);

View File

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

View File

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

View File

@ -107,7 +107,7 @@ void test_expiration(high_resolution_clock::duration const& expiry_time
{
default_config cfg;
simulation sim(cfg);
sim::asio::io_service ios(sim, asio::ip::address_v4::from_string("10.0.0.1"));
sim::asio::io_service ios(sim, addr("10.0.0.1"));
sim::asio::high_resolution_timer timer(ios);
timer.expires_from_now(expiry_time);
@ -139,16 +139,15 @@ TORRENT_TEST(dht_storage_counters)
s->announce_peer(n2, p3, "torrent_name1", false);
s->announce_peer(n3, p4, "torrent_name2", false);
s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21"));
s->put_immutable_item(n4, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n1, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n2, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n3, {"123", 3}, addr("124.31.75.21"));
s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21"));
s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21"));
s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21"));
char public_key[item_pk_len];
char signature[item_sig_len];
s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4
, address::from_string("124.31.75.21"));
dht::public_key pk;
dht::signature sig;
s->put_mutable_item(n4, {"123", 3}, sig, sequence_number(1), pk, {"salt", 4}
, addr("124.31.75.21"));
dht_storage_counters c;
// note that we are using the aux global timer

View File

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

View File

@ -303,14 +303,14 @@ namespace libtorrent
bdecode_node::operator bool() const
{ 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);
bdecode_token const& t = m_root_tokens[m_token_idx];
bdecode_token const& next = m_root_tokens[m_token_idx + t.next_item];
return std::make_pair(m_buffer + t.offset, next.offset - t.offset);
return { m_buffer + t.offset, size_t(next.offset - t.offset) };
}
bdecode_node bdecode_node::list_at(int i) const

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -96,11 +96,9 @@ namespace libtorrent
std::array<char, 96> buffer;
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
hasher h;
h.update("req3", 4);
h.update(buffer);
m_xor_mask = h.final();
m_xor_mask = hasher(req3).update(buffer).final();
}
std::tuple<int, span<aux::const_buffer>>
@ -148,7 +146,7 @@ namespace libtorrent
if (num_bufs != 0)
{
std::tie(next_barrier, out_iovec)
= m_send_barriers.front().enc_handler->encrypt({bufs, num_bufs});
= m_send_barriers.front().enc_handler->encrypt({bufs, size_t(num_bufs)});
}
if (m_send_barriers.front().next != INT_MAX)

View File

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

View File

@ -521,6 +521,8 @@ namespace libtorrent
#endif
}
// TODO: 3 expose the sequence_number, public_key, secret_key and signature
// types to the client
sha1_hash session_handle::dht_put_item(entry data)
{
std::vector<char> buf;

View File

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

View File

@ -195,7 +195,7 @@ namespace
h.update(j->buffer.disk_block, j->d.io.buffer_size);
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);
// there is no peer with this address anymore
@ -270,7 +270,7 @@ namespace
hasher h;
h.update(j->buffer.disk_block, j->d.io.buffer_size);
h.update(reinterpret_cast<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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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