Merge pull request #178 from thomas-yuan/put
Make dht_put_alert more accurate.
This commit is contained in:
commit
42b129b9d5
|
@ -127,6 +127,7 @@ set(kademlia_sources
|
||||||
refresh
|
refresh
|
||||||
rpc_manager
|
rpc_manager
|
||||||
find_data
|
find_data
|
||||||
|
put_data
|
||||||
node_id
|
node_id
|
||||||
routing_table
|
routing_table
|
||||||
traversal_algorithm
|
traversal_algorithm
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -706,6 +706,7 @@ KADEMLIA_SOURCES =
|
||||||
get_peers
|
get_peers
|
||||||
item
|
item
|
||||||
get_item
|
get_item
|
||||||
|
put_data
|
||||||
;
|
;
|
||||||
|
|
||||||
ED25519_SOURCES =
|
ED25519_SOURCES =
|
||||||
|
|
|
@ -187,6 +187,7 @@ nobase_include_HEADERS = \
|
||||||
kademlia/direct_request.hpp \
|
kademlia/direct_request.hpp \
|
||||||
kademlia/dos_blocker.hpp \
|
kademlia/dos_blocker.hpp \
|
||||||
kademlia/find_data.hpp \
|
kademlia/find_data.hpp \
|
||||||
|
kademlia/put_data.hpp \
|
||||||
kademlia/msg.hpp \
|
kademlia/msg.hpp \
|
||||||
kademlia/node.hpp \
|
kademlia/node.hpp \
|
||||||
kademlia/node_entry.hpp \
|
kademlia/node_entry.hpp \
|
||||||
|
|
|
@ -2045,11 +2045,12 @@ namespace libtorrent
|
||||||
struct TORRENT_EXPORT dht_put_alert: alert
|
struct TORRENT_EXPORT dht_put_alert: alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
dht_put_alert(aux::stack_allocator& alloc, sha1_hash const& t);
|
dht_put_alert(aux::stack_allocator& alloc, sha1_hash const& t, int n);
|
||||||
dht_put_alert(aux::stack_allocator& alloc, boost::array<char, 32> key
|
dht_put_alert(aux::stack_allocator& alloc, boost::array<char, 32> key
|
||||||
, boost::array<char, 64> sig
|
, boost::array<char, 64> sig
|
||||||
, std::string s
|
, std::string s
|
||||||
, boost::uint64_t sequence_number);
|
, boost::uint64_t sequence_number
|
||||||
|
, int n);
|
||||||
|
|
||||||
TORRENT_DEFINE_ALERT(dht_put_alert, 76)
|
TORRENT_DEFINE_ALERT(dht_put_alert, 76)
|
||||||
|
|
||||||
|
@ -2066,6 +2067,12 @@ namespace libtorrent
|
||||||
boost::array<char, 64> signature;
|
boost::array<char, 64> signature;
|
||||||
std::string salt;
|
std::string salt;
|
||||||
boost::uint64_t seq;
|
boost::uint64_t seq;
|
||||||
|
|
||||||
|
// DHT put operation usually writes item to k nodes, maybe the node
|
||||||
|
// is stale so no response, or the node doesn't support 'put', or the
|
||||||
|
// token for write is out of date, etc. num_success is the number of
|
||||||
|
// successful responses we got from the puts.
|
||||||
|
int num_success;
|
||||||
};
|
};
|
||||||
|
|
||||||
// this alert is used to report errors in the i2p SAM connection
|
// this alert is used to report errors in the i2p SAM connection
|
||||||
|
|
|
@ -101,11 +101,18 @@ namespace libtorrent { namespace dht
|
||||||
, boost::function<void(item const&, bool)> cb
|
, boost::function<void(item const&, bool)> cb
|
||||||
, std::string salt = std::string());
|
, std::string salt = std::string());
|
||||||
|
|
||||||
|
// for immutable_item.
|
||||||
|
// the callback function will be called when put operation is done.
|
||||||
|
// the int parameter indicates the success numbers of put operation.
|
||||||
void put_item(entry data
|
void put_item(entry data
|
||||||
, boost::function<void()> cb);
|
, boost::function<void(int)> cb);
|
||||||
|
|
||||||
|
// 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(char const* key
|
||||||
, boost::function<void(item&)> cb, std::string salt = std::string());
|
, boost::function<void(item&, int)> cb
|
||||||
|
, boost::function<void(item&)> data_cb, std::string salt = std::string());
|
||||||
|
|
||||||
// send an arbitrary DHT request directly to a node
|
// send an arbitrary DHT request directly to a node
|
||||||
void direct_request(udp::endpoint ep, entry& e
|
void direct_request(udp::endpoint ep, entry& e
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace libtorrent { namespace dht
|
||||||
class get_item : public find_data
|
class get_item : public find_data
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef boost::function<bool(item&, bool)> data_callback;
|
typedef boost::function<void(item&, bool)> data_callback;
|
||||||
|
|
||||||
void got_data(bdecode_node const& v,
|
void got_data(bdecode_node const& v,
|
||||||
char const* pk,
|
char const* pk,
|
||||||
|
@ -53,13 +53,15 @@ public:
|
||||||
// for immutable itms
|
// for immutable itms
|
||||||
get_item(node& dht_node
|
get_item(node& dht_node
|
||||||
, node_id target
|
, node_id target
|
||||||
, data_callback const& dcallback);
|
, data_callback const& dcallback
|
||||||
|
, nodes_callback const& ncallback);
|
||||||
|
|
||||||
// for mutable items
|
// for mutable items
|
||||||
get_item(node& dht_node
|
get_item(node& dht_node
|
||||||
, char const* pk
|
, char const* pk
|
||||||
, std::string const& salt
|
, std::string const& salt
|
||||||
, data_callback const& dcallback);
|
, data_callback const& dcallback
|
||||||
|
, nodes_callback const& ncallback);
|
||||||
|
|
||||||
virtual char const* name() const;
|
virtual char const* name() const;
|
||||||
|
|
||||||
|
@ -68,11 +70,10 @@ protected:
|
||||||
virtual bool invoke(observer_ptr o);
|
virtual bool invoke(observer_ptr o);
|
||||||
virtual void done();
|
virtual void done();
|
||||||
|
|
||||||
void put(std::vector<std::pair<node_entry, std::string> > const& v);
|
|
||||||
|
|
||||||
data_callback m_data_callback;
|
data_callback m_data_callback;
|
||||||
item m_data;
|
item m_data;
|
||||||
std::string m_salt;
|
std::string m_salt;
|
||||||
|
bool m_immutable;
|
||||||
};
|
};
|
||||||
|
|
||||||
class get_item_observer : public find_data_observer
|
class get_item_observer : public find_data_observer
|
||||||
|
|
|
@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <libtorrent/kademlia/node_id.hpp>
|
#include <libtorrent/kademlia/node_id.hpp>
|
||||||
#include <libtorrent/kademlia/msg.hpp>
|
#include <libtorrent/kademlia/msg.hpp>
|
||||||
#include <libtorrent/kademlia/find_data.hpp>
|
#include <libtorrent/kademlia/find_data.hpp>
|
||||||
|
#include <libtorrent/kademlia/put_data.hpp>
|
||||||
#include <libtorrent/kademlia/item.hpp>
|
#include <libtorrent/kademlia/item.hpp>
|
||||||
|
|
||||||
#include <libtorrent/io.hpp>
|
#include <libtorrent/io.hpp>
|
||||||
|
@ -176,8 +177,13 @@ public:
|
||||||
void direct_request(udp::endpoint ep, entry& e
|
void direct_request(udp::endpoint ep, entry& e
|
||||||
, boost::function<void(msg const&)> f);
|
, boost::function<void(msg const&)> f);
|
||||||
|
|
||||||
void get_item(sha1_hash const& target, boost::function<bool(item&, bool)> f);
|
void get_item(sha1_hash const& target, boost::function<void(item&)> f);
|
||||||
void get_item(char const* pk, std::string const& salt, boost::function<bool(item&, bool)> f);
|
void get_item(char const* pk, std::string const& salt, boost::function<void(item&, bool)> f);
|
||||||
|
|
||||||
|
void put_item(sha1_hash const& target, entry& data, boost::function<void(int)> f);
|
||||||
|
void put_item(char const* pk, std::string const& salt
|
||||||
|
, boost::function<void(item&, 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, char const* info_hash
|
||||||
, udp::endpoint const& addr) const;
|
, udp::endpoint const& addr) const;
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, Arvid Norberg, Thomas Yuan
|
||||||
|
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 TORRENT_PUT_DATA_HPP
|
||||||
|
#define TORRENT_PUT_DATA_HPP
|
||||||
|
|
||||||
|
#include <libtorrent/kademlia/traversal_algorithm.hpp>
|
||||||
|
#include <libtorrent/kademlia/node_id.hpp>
|
||||||
|
#include <libtorrent/kademlia/observer.hpp>
|
||||||
|
#include <libtorrent/kademlia/item.hpp>
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||||
|
|
||||||
|
#include <boost/function/function1.hpp>
|
||||||
|
#include <boost/function/function2.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||||
|
|
||||||
|
namespace libtorrent { namespace dht
|
||||||
|
{
|
||||||
|
struct msg;
|
||||||
|
class node;
|
||||||
|
|
||||||
|
struct put_data: traversal_algorithm
|
||||||
|
{
|
||||||
|
typedef boost::function<void(item&, int)> put_callback;
|
||||||
|
|
||||||
|
put_data(node& node, put_callback const& callback);
|
||||||
|
|
||||||
|
virtual char const* name() const;
|
||||||
|
|
||||||
|
void set_data(item const& data) { m_data = data; }
|
||||||
|
|
||||||
|
void set_targets(std::vector<std::pair<node_entry, std::string> > const& targets);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
virtual void done();
|
||||||
|
virtual bool invoke(observer_ptr o);
|
||||||
|
|
||||||
|
put_callback m_put_callback;
|
||||||
|
item m_data;
|
||||||
|
bool m_done;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct put_data_observer : traversal_observer
|
||||||
|
{
|
||||||
|
put_data_observer(
|
||||||
|
boost::intrusive_ptr<traversal_algorithm> const& algorithm
|
||||||
|
, udp::endpoint const& ep, node_id const& id, std::string const& token)
|
||||||
|
: traversal_observer(algorithm, ep, id)
|
||||||
|
, m_token(token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reply(msg const&) { done(); }
|
||||||
|
|
||||||
|
std::string m_token;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } // namespace libtorrent::dht
|
||||||
|
|
||||||
|
#endif // TORRENT_PUT_DATA_HPP
|
||||||
|
|
|
@ -7,6 +7,7 @@ KADEMLIA_SOURCES = \
|
||||||
kademlia/dht_storage.cpp \
|
kademlia/dht_storage.cpp \
|
||||||
kademlia/dht_tracker.cpp \
|
kademlia/dht_tracker.cpp \
|
||||||
kademlia/find_data.cpp \
|
kademlia/find_data.cpp \
|
||||||
|
kademlia/put_data.cpp \
|
||||||
kademlia/node.cpp \
|
kademlia/node.cpp \
|
||||||
kademlia/node_entry.cpp \
|
kademlia/node_entry.cpp \
|
||||||
kademlia/node_id.cpp \
|
kademlia/node_id.cpp \
|
||||||
|
|
|
@ -1472,21 +1472,24 @@ namespace libtorrent {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
dht_put_alert::dht_put_alert(aux::stack_allocator&, sha1_hash const& t)
|
dht_put_alert::dht_put_alert(aux::stack_allocator&, sha1_hash const& t, int n)
|
||||||
: target(t)
|
: target(t)
|
||||||
, seq(0)
|
, seq(0)
|
||||||
|
, num_success(n)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
dht_put_alert::dht_put_alert(aux::stack_allocator&
|
dht_put_alert::dht_put_alert(aux::stack_allocator&
|
||||||
, boost::array<char, 32> key
|
, boost::array<char, 32> key
|
||||||
, boost::array<char, 64> sig
|
, boost::array<char, 64> sig
|
||||||
, std::string s
|
, std::string s
|
||||||
, boost::uint64_t sequence_number)
|
, boost::uint64_t sequence_number
|
||||||
|
, int n)
|
||||||
: target(0)
|
: target(0)
|
||||||
, public_key(key)
|
, public_key(key)
|
||||||
, signature(sig)
|
, signature(sig)
|
||||||
, salt(s)
|
, salt(s)
|
||||||
, seq(sequence_number)
|
, seq(sequence_number)
|
||||||
|
, num_success(n)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string dht_put_alert::message() const
|
std::string dht_put_alert::message() const
|
||||||
|
@ -1494,7 +1497,8 @@ namespace libtorrent {
|
||||||
char msg[1050];
|
char msg[1050];
|
||||||
if (target.is_all_zeros())
|
if (target.is_all_zeros())
|
||||||
{
|
{
|
||||||
snprintf(msg, sizeof(msg), "DHT put complete (key=%s sig=%s salt=%s seq=%" PRId64 ")"
|
snprintf(msg, sizeof(msg), "DHT put complete (success=%d key=%s sig=%s salt=%s seq=%" PRId64 ")"
|
||||||
|
, num_success
|
||||||
, to_hex(std::string(&public_key[0], 32)).c_str()
|
, to_hex(std::string(&public_key[0], 32)).c_str()
|
||||||
, to_hex(std::string(&signature[0], 64)).c_str()
|
, to_hex(std::string(&signature[0], 64)).c_str()
|
||||||
, salt.c_str()
|
, salt.c_str()
|
||||||
|
@ -1502,7 +1506,8 @@ namespace libtorrent {
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(msg, sizeof(msg), "DHT put complete (hash=%s)"
|
snprintf(msg, sizeof(msg), "DHT put commplete (success=%d hash=%s)"
|
||||||
|
, num_success
|
||||||
, to_hex(target.to_string()).c_str());
|
, to_hex(target.to_string()).c_str());
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,53 +239,10 @@ namespace libtorrent { namespace dht
|
||||||
m_dht.announce(ih, listen_port, flags, f);
|
m_dht.announce(ih, listen_port, flags, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
// these functions provide a slightly higher level
|
|
||||||
// interface to the get/put functionality in the DHT
|
|
||||||
bool get_immutable_item_callback(item& it, boost::function<void(item const&)> f)
|
|
||||||
{
|
|
||||||
// the reason to wrap here is to control the return value
|
|
||||||
// since it controls whether we re-put the content
|
|
||||||
TORRENT_ASSERT(!it.is_mutable());
|
|
||||||
f(it);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_mutable_item_callback(item& it, bool authoritative, boost::function<void(item const&, bool)> f)
|
|
||||||
{
|
|
||||||
// the reason to wrap here is to control the return value
|
|
||||||
// since it controls whether we re-put the content
|
|
||||||
TORRENT_ASSERT(it.is_mutable());
|
|
||||||
f(it, authoritative);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool put_immutable_item_callback(item& it, boost::function<void()> f
|
|
||||||
, entry data)
|
|
||||||
{
|
|
||||||
TORRENT_ASSERT(!it.is_mutable());
|
|
||||||
it.assign(data);
|
|
||||||
// TODO: ideally this function would be called when the
|
|
||||||
// put completes
|
|
||||||
f();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool put_mutable_item_callback(item& it, bool authoritative, boost::function<void(item&)> cb)
|
|
||||||
{
|
|
||||||
if (authoritative) {
|
|
||||||
cb(it);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void dht_tracker::get_item(sha1_hash const& target
|
void dht_tracker::get_item(sha1_hash const& target
|
||||||
, boost::function<void(item const&)> cb)
|
, boost::function<void(item const&)> cb)
|
||||||
{
|
{
|
||||||
m_dht.get_item(target, boost::bind(&get_immutable_item_callback, _1, cb));
|
m_dht.get_item(target, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// key is a 32-byte binary string, the public key to look up.
|
// key is a 32-byte binary string, the public key to look up.
|
||||||
|
@ -294,26 +251,25 @@ namespace libtorrent { namespace dht
|
||||||
, boost::function<void(item const&, bool)> cb
|
, boost::function<void(item const&, bool)> cb
|
||||||
, std::string salt)
|
, std::string salt)
|
||||||
{
|
{
|
||||||
m_dht.get_item(key, salt, boost::bind(&get_mutable_item_callback, _1, _2, cb));
|
m_dht.get_item(key, salt, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dht_tracker::put_item(entry data
|
void dht_tracker::put_item(entry data
|
||||||
, boost::function<void()> cb)
|
, boost::function<void(int)> cb)
|
||||||
{
|
{
|
||||||
std::string flat_data;
|
std::string flat_data;
|
||||||
bencode(std::back_inserter(flat_data), data);
|
bencode(std::back_inserter(flat_data), data);
|
||||||
sha1_hash target = item_target_id(
|
sha1_hash target = item_target_id(
|
||||||
std::pair<char const*, int>(flat_data.c_str(), flat_data.size()));
|
std::pair<char const*, int>(flat_data.c_str(), flat_data.size()));
|
||||||
|
|
||||||
m_dht.get_item(target, boost::bind(&put_immutable_item_callback
|
m_dht.put_item(target, data, cb);
|
||||||
, _1, cb, data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dht_tracker::put_item(char const* key
|
void dht_tracker::put_item(char const* key
|
||||||
, boost::function<void(item&)> cb, std::string salt)
|
, boost::function<void(item&, int)> cb
|
||||||
|
, boost::function<void(item&)> data_cb, std::string salt)
|
||||||
{
|
{
|
||||||
m_dht.get_item(key, salt, boost::bind(&put_mutable_item_callback
|
m_dht.put_item(key, salt, cb, data_cb);
|
||||||
, _1, _2, cb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dht_tracker::direct_request(udp::endpoint ep, entry& e
|
void dht_tracker::direct_request(udp::endpoint ep, entry& e
|
||||||
|
|
|
@ -50,78 +50,64 @@ void get_item::got_data(bdecode_node const& v,
|
||||||
char const* sig)
|
char const* sig)
|
||||||
{
|
{
|
||||||
// we received data!
|
// we received data!
|
||||||
|
// if no data_callback, we needn't care about the data we get.
|
||||||
|
// only put_immutable_item no data_callback
|
||||||
|
if (!m_data_callback) return;
|
||||||
|
|
||||||
std::pair<char const*, int> salt(m_salt.c_str(), int(m_salt.size()));
|
// for get_immutable_item
|
||||||
|
if (m_immutable)
|
||||||
sha1_hash incoming_target;
|
|
||||||
if (pk)
|
|
||||||
incoming_target = item_target_id(salt, pk);
|
|
||||||
else
|
|
||||||
incoming_target = item_target_id(v.data_section());
|
|
||||||
|
|
||||||
if (incoming_target != m_target) return;
|
|
||||||
|
|
||||||
if (pk && sig)
|
|
||||||
{
|
{
|
||||||
// this is mutable data. If it passes the signature
|
// If m_data isn't empty, we should have post alert.
|
||||||
// check, remember it. Just keep the version with
|
if (!m_data.empty()) return;
|
||||||
// the highest sequence number.
|
|
||||||
if (m_data.empty() || m_data.seq() < seq)
|
|
||||||
{
|
|
||||||
if (!m_data.assign(v, salt, seq, pk, sig))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// for get_item, we should call callback when we get data,
|
sha1_hash incoming_target = item_target_id(v.data_section());
|
||||||
// even if the date is not authoritative, we can update later.
|
if (incoming_target != m_target) return;
|
||||||
// so caller can get response ASAP without waitting transaction
|
|
||||||
// time-out (15 seconds).
|
|
||||||
// for put_item, the callback function will do nothing
|
|
||||||
// if the data is non-authoritative.
|
|
||||||
// we can just ignore the return value here since for mutable
|
|
||||||
// data, we always need the transaction done.
|
|
||||||
m_data_callback(m_data, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_data.empty())
|
|
||||||
{
|
|
||||||
// this is the first time we receive data,
|
|
||||||
// and it's immutable
|
|
||||||
|
|
||||||
m_data.assign(v);
|
m_data.assign(v);
|
||||||
bool put_requested = m_data_callback(m_data, true);
|
|
||||||
|
|
||||||
// if we intend to put, we need to keep going
|
// There can only be one true immutable item with a given id
|
||||||
// until we find the closest nodes, since those
|
// Now that we've got it and the user doesn't want to do a put
|
||||||
// are the ones we're putting to
|
// there's no point in continuing to query other nodes
|
||||||
if (put_requested)
|
m_data_callback(m_data, true);
|
||||||
{
|
done();
|
||||||
#if TORRENT_USE_ASSERTS
|
|
||||||
std::vector<char> buffer;
|
|
||||||
bencode(std::back_inserter(buffer), m_data.value());
|
|
||||||
TORRENT_ASSERT(m_target == hasher(&buffer[0], buffer.size()).final());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this function is called when we're done, passing
|
return;
|
||||||
// in all relevant nodes we received data from close
|
}
|
||||||
// to the target.
|
|
||||||
m_nodes_callback = boost::bind(&get_item::put, this, _1);
|
// immutalbe data should has been handled before this line, only mutable
|
||||||
}
|
// data can reach here, which means pk and sig must be valid.
|
||||||
else
|
if (!pk || !sig) return;
|
||||||
{
|
|
||||||
// There can only be one true immutable item with a given id
|
std::pair<char const*, int> salt(m_salt.c_str(), int(m_salt.size()));
|
||||||
// Now that we've got it and the user doesn't want to do a put
|
sha1_hash incoming_target = item_target_id(salt, pk);
|
||||||
// there's no point in continuing to query other nodes
|
if (incoming_target != m_target) return;
|
||||||
done();
|
|
||||||
}
|
// this is mutable data. If it passes the signature
|
||||||
|
// check, remember it. Just keep the version with
|
||||||
|
// the highest sequence number.
|
||||||
|
if (m_data.empty() || m_data.seq() < seq)
|
||||||
|
{
|
||||||
|
if (!m_data.assign(v, salt, seq, pk, sig))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// for get_item, we should call callback when we get data,
|
||||||
|
// even if the date is not authoritative, we can update later.
|
||||||
|
// so caller can get response ASAP without waitting transaction
|
||||||
|
// time-out (15 seconds).
|
||||||
|
// for put_item, the callback function will do nothing
|
||||||
|
// if the data is non-authoritative.
|
||||||
|
m_data_callback(m_data, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get_item::get_item(
|
get_item::get_item(
|
||||||
node& dht_node
|
node& dht_node
|
||||||
, node_id target
|
, node_id target
|
||||||
, data_callback const& dcallback)
|
, data_callback const& dcallback
|
||||||
: find_data(dht_node, target, nodes_callback())
|
, nodes_callback const& ncallback)
|
||||||
|
: find_data(dht_node, target, ncallback)
|
||||||
, m_data_callback(dcallback)
|
, m_data_callback(dcallback)
|
||||||
|
, m_immutable(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,12 +115,14 @@ get_item::get_item(
|
||||||
node& dht_node
|
node& dht_node
|
||||||
, char const* pk
|
, char const* pk
|
||||||
, std::string const& salt
|
, std::string const& salt
|
||||||
, data_callback const& dcallback)
|
, data_callback const& dcallback
|
||||||
|
, nodes_callback const& ncallback)
|
||||||
: find_data(dht_node, item_target_id(
|
: find_data(dht_node, item_target_id(
|
||||||
std::make_pair(salt.c_str(), int(salt.size())), pk)
|
std::make_pair(salt.c_str(), int(salt.size())), pk)
|
||||||
, nodes_callback())
|
, ncallback)
|
||||||
, m_data_callback(dcallback)
|
, m_data_callback(dcallback)
|
||||||
, m_data(pk, salt)
|
, m_data(pk, salt)
|
||||||
|
, m_immutable(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,92 +158,28 @@ bool get_item::invoke(observer_ptr o)
|
||||||
|
|
||||||
void get_item::done()
|
void get_item::done()
|
||||||
{
|
{
|
||||||
|
// no data_callback for immutable item put
|
||||||
|
if (!m_data_callback) return find_data::done();
|
||||||
|
|
||||||
if (m_data.is_mutable() || m_data.empty())
|
if (m_data.is_mutable() || m_data.empty())
|
||||||
{
|
{
|
||||||
// for mutable data, now we have authoritative data since
|
// for mutable data, now we have authoritative data since
|
||||||
// we've heard from everyone, to be sure we got the
|
// we've heard from everyone, to be sure we got the
|
||||||
// latest version of the data (i.e. highest sequence number)
|
// latest version of the data (i.e. highest sequence number)
|
||||||
bool put_requested = m_data_callback(m_data, true);
|
m_data_callback(m_data, true);
|
||||||
if (put_requested)
|
|
||||||
{
|
|
||||||
#if TORRENT_USE_ASSERTS
|
#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()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::vector<char> buffer;
|
|
||||||
bencode(std::back_inserter(buffer), m_data.value());
|
|
||||||
TORRENT_ASSERT(m_target == hasher(&buffer[0], buffer.size()).final());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// this function is called when we're done, passing
|
|
||||||
// in all relevant nodes we received data from close
|
|
||||||
// to the target.
|
|
||||||
m_nodes_callback = boost::bind(&get_item::put, this, _1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
find_data::done();
|
|
||||||
}
|
|
||||||
|
|
||||||
// this function sends a put message to the nodes
|
|
||||||
// closest to the target. Those nodes are passed in
|
|
||||||
// as the v argument
|
|
||||||
void get_item::put(std::vector<std::pair<node_entry, std::string> > const& v)
|
|
||||||
{
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
// TODO: 3 it would be nice to not have to spend so much time rendering
|
|
||||||
// the bencoded dict if logging is disabled
|
|
||||||
get_node().observer()->log(dht_logger::traversal, "[%p] sending put "
|
|
||||||
"[ seq: %" PRId64 " nodes: %d ]"
|
|
||||||
, static_cast<void*>(this), (m_data.is_mutable() ? m_data.seq() : -1)
|
|
||||||
, int(v.size()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// create a dummy traversal_algorithm
|
|
||||||
boost::intrusive_ptr<traversal_algorithm> algo(
|
|
||||||
new traversal_algorithm(m_node, (node_id::min)()));
|
|
||||||
|
|
||||||
// store on the first k nodes
|
|
||||||
for (std::vector<std::pair<node_entry, std::string> >::const_iterator i = v.begin()
|
|
||||||
, end(v.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
|
||||||
get_node().observer()->log(dht_logger::traversal, "[%p] put-distance: %d"
|
|
||||||
, static_cast<void*>(this), 160 - distance_exp(m_target, i->first.id));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void* ptr = m_node.m_rpc.allocate_observer();
|
|
||||||
if (ptr == 0) return;
|
|
||||||
|
|
||||||
// TODO: 3 we don't support CAS errors here! we need a custom observer
|
|
||||||
observer_ptr o(new (ptr) announce_observer(algo, i->first.ep(), i->first.id));
|
|
||||||
#if TORRENT_USE_ASSERTS
|
|
||||||
o->m_in_constructor = false;
|
|
||||||
#endif
|
|
||||||
entry e;
|
|
||||||
e["y"] = "q";
|
|
||||||
e["q"] = "put";
|
|
||||||
entry& a = e["a"];
|
|
||||||
a["v"] = m_data.value();
|
|
||||||
a["token"] = i->second;
|
|
||||||
if (m_data.is_mutable())
|
if (m_data.is_mutable())
|
||||||
{
|
{
|
||||||
a["k"] = std::string(m_data.pk().data(), item_pk_len);
|
TORRENT_ASSERT(m_target
|
||||||
a["seq"] = m_data.seq();
|
== item_target_id(std::pair<char const*, int>(m_data.salt().c_str()
|
||||||
a["sig"] = std::string(m_data.sig().data(), item_sig_len);
|
, m_data.salt().size())
|
||||||
if (!m_data.salt().empty())
|
, m_data.pk().data()));
|
||||||
{
|
|
||||||
a["salt"] = m_data.salt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_node.m_rpc.invoke(e, i->first.ep(), o);
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
find_data::done();
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_item_observer::reply(msg const& m)
|
void get_item_observer::reply(msg const& m)
|
||||||
|
|
|
@ -315,7 +315,6 @@ namespace
|
||||||
// create a dummy traversal_algorithm
|
// create a dummy traversal_algorithm
|
||||||
boost::intrusive_ptr<traversal_algorithm> algo(
|
boost::intrusive_ptr<traversal_algorithm> algo(
|
||||||
new traversal_algorithm(node, (node_id::min)()));
|
new traversal_algorithm(node, (node_id::min)()));
|
||||||
|
|
||||||
// store on the first k nodes
|
// store on the first k nodes
|
||||||
for (std::vector<std::pair<node_entry, std::string> >::const_iterator i = v.begin()
|
for (std::vector<std::pair<node_entry, std::string> >::const_iterator i = v.begin()
|
||||||
, end(v.end()); i != end; ++i)
|
, end(v.end()); i != end; ++i)
|
||||||
|
@ -424,7 +423,7 @@ void node::direct_request(udp::endpoint ep, entry& e
|
||||||
}
|
}
|
||||||
|
|
||||||
void node::get_item(sha1_hash const& target
|
void node::get_item(sha1_hash const& target
|
||||||
, boost::function<bool(item&, bool)> f)
|
, boost::function<void(item&)> f)
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (m_observer)
|
if (m_observer)
|
||||||
|
@ -437,12 +436,12 @@ void node::get_item(sha1_hash const& target
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::intrusive_ptr<dht::get_item> ta;
|
boost::intrusive_ptr<dht::get_item> ta;
|
||||||
ta.reset(new dht::get_item(*this, target, f));
|
ta.reset(new dht::get_item(*this, target, boost::bind(f, _1), find_data::nodes_callback()));
|
||||||
ta->start();
|
ta->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void node::get_item(char const* pk, std::string const& salt
|
void node::get_item(char const* pk, std::string const& salt
|
||||||
, boost::function<bool(item&, bool)> f)
|
, boost::function<void(item&, bool)> f)
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (m_observer)
|
if (m_observer)
|
||||||
|
@ -454,7 +453,77 @@ void node::get_item(char const* pk, std::string const& salt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
boost::intrusive_ptr<dht::get_item> ta;
|
boost::intrusive_ptr<dht::get_item> ta;
|
||||||
ta.reset(new dht::get_item(*this, pk, salt, f));
|
ta.reset(new dht::get_item(*this, pk, salt, f, find_data::nodes_callback()));
|
||||||
|
ta->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void put(std::vector<std::pair<node_entry, std::string> > const& nodes
|
||||||
|
, boost::intrusive_ptr<dht::put_data> ta)
|
||||||
|
{
|
||||||
|
ta->set_targets(nodes);
|
||||||
|
ta->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_data_cb(item& i, bool auth
|
||||||
|
, boost::intrusive_ptr<put_data> ta
|
||||||
|
, boost::function<void(item&)> f)
|
||||||
|
{
|
||||||
|
// call data_callback only when we got authoritative data.
|
||||||
|
if (auth)
|
||||||
|
{
|
||||||
|
f(i);
|
||||||
|
ta->set_data(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void node::put_item(sha1_hash const& target, entry& data, boost::function<void(int)> f)
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
if (m_observer)
|
||||||
|
{
|
||||||
|
char hex_target[41];
|
||||||
|
to_hex(target.data(), 20, hex_target);
|
||||||
|
m_observer->log(dht_logger::node, "starting get for [ hash: %s ]"
|
||||||
|
, hex_target);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
item i;
|
||||||
|
i.assign(data);
|
||||||
|
boost::intrusive_ptr<dht::put_data> put_ta;
|
||||||
|
put_ta.reset(new dht::put_data(*this, boost::bind(f, _2)));
|
||||||
|
put_ta->set_data(i);
|
||||||
|
|
||||||
|
boost::intrusive_ptr<dht::get_item> ta;
|
||||||
|
ta.reset(new dht::get_item(*this, target, get_item::data_callback(),
|
||||||
|
boost::bind(&put, _1, put_ta)));
|
||||||
|
ta->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void node::put_item(char const* pk, std::string const& salt
|
||||||
|
, boost::function<void(item&, int)> f
|
||||||
|
, boost::function<void(item&)> data_cb)
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
if (m_observer)
|
||||||
|
{
|
||||||
|
char hex_key[65];
|
||||||
|
to_hex(pk, 32, hex_key);
|
||||||
|
m_observer->log(dht_logger::node, "starting get for [ key: %s ]", hex_key);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
boost::intrusive_ptr<dht::put_data> put_ta;
|
||||||
|
put_ta.reset(new dht::put_data(*this, f));
|
||||||
|
|
||||||
|
boost::intrusive_ptr<dht::get_item> ta;
|
||||||
|
ta.reset(new dht::get_item(*this, pk, salt
|
||||||
|
, boost::bind(&put_data_cb, _1, _2, put_ta, data_cb)
|
||||||
|
, boost::bind(&put, _1, put_ta)));
|
||||||
ta->start();
|
ta->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2006-2015, Arvid Norberg & Daniel Wallin
|
||||||
|
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.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <libtorrent/kademlia/put_data.hpp>
|
||||||
|
#include <libtorrent/kademlia/dht_observer.hpp>
|
||||||
|
#include <libtorrent/kademlia/node.hpp>
|
||||||
|
#include <libtorrent/io.hpp>
|
||||||
|
|
||||||
|
namespace libtorrent { namespace dht
|
||||||
|
{
|
||||||
|
|
||||||
|
put_data::put_data(node& dht_node, put_callback const& callback)
|
||||||
|
: traversal_algorithm(dht_node, (node_id::min)())
|
||||||
|
, m_put_callback(callback)
|
||||||
|
, m_done(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* put_data::name() const { return "put_data"; }
|
||||||
|
|
||||||
|
void put_data::set_targets(std::vector<std::pair<node_entry, std::string> > const& targets)
|
||||||
|
{
|
||||||
|
for (std::vector<std::pair<node_entry, std::string> >::const_iterator i = targets.begin()
|
||||||
|
, end(targets.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
void* ptr = m_node.m_rpc.allocate_observer();
|
||||||
|
if (ptr == 0) return;
|
||||||
|
|
||||||
|
observer_ptr o(new (ptr) put_data_observer(this, i->first.ep()
|
||||||
|
, i->first.id, i->second));
|
||||||
|
|
||||||
|
#if defined TORRENT_DEBUG || defined TORRENT_RELEASE_ASSERTS
|
||||||
|
o->m_in_constructor = false;
|
||||||
|
#endif
|
||||||
|
m_results.push_back(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_data::done()
|
||||||
|
{
|
||||||
|
if (m_invoke_count != 0) return;
|
||||||
|
m_done = true;
|
||||||
|
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
get_node().observer()->log(dht_logger::traversal, "[%p] %s DONE, response %d, timeout %d"
|
||||||
|
, static_cast<void*>(this), name(), m_responses, m_timeouts);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_put_callback(m_data, m_responses);
|
||||||
|
traversal_algorithm::done();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool put_data::invoke(observer_ptr o)
|
||||||
|
{
|
||||||
|
if (m_done)
|
||||||
|
{
|
||||||
|
m_invoke_count = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
put_data_observer* po = static_cast<put_data_observer*>(o.get());
|
||||||
|
|
||||||
|
entry e;
|
||||||
|
e["y"] = "q";
|
||||||
|
e["q"] = "put";
|
||||||
|
entry& a = e["a"];
|
||||||
|
a["v"] = m_data.value();
|
||||||
|
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);
|
||||||
|
if (!m_data.salt().empty())
|
||||||
|
{
|
||||||
|
a["salt"] = m_data.salt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_node.m_rpc.invoke(e, o->target_ep(), o);
|
||||||
|
}
|
||||||
|
|
||||||
|
} } // namespace libtorrent::dht
|
||||||
|
|
|
@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <libtorrent/kademlia/rpc_manager.hpp>
|
#include <libtorrent/kademlia/rpc_manager.hpp>
|
||||||
#include <libtorrent/kademlia/routing_table.hpp>
|
#include <libtorrent/kademlia/routing_table.hpp>
|
||||||
#include <libtorrent/kademlia/find_data.hpp>
|
#include <libtorrent/kademlia/find_data.hpp>
|
||||||
|
#include <libtorrent/kademlia/put_data.hpp>
|
||||||
#include <libtorrent/kademlia/refresh.hpp>
|
#include <libtorrent/kademlia/refresh.hpp>
|
||||||
#include <libtorrent/kademlia/node.hpp>
|
#include <libtorrent/kademlia/node.hpp>
|
||||||
#include <libtorrent/kademlia/observer.hpp>
|
#include <libtorrent/kademlia/observer.hpp>
|
||||||
|
@ -158,7 +159,7 @@ void observer::set_id(node_id const& id)
|
||||||
enum { observer_size = max3<
|
enum { observer_size = max3<
|
||||||
sizeof(find_data_observer)
|
sizeof(find_data_observer)
|
||||||
, sizeof(announce_observer)
|
, sizeof(announce_observer)
|
||||||
, sizeof(null_observer)
|
, sizeof(put_data_observer)
|
||||||
>::value
|
>::value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5648,13 +5648,24 @@ retry:
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
void on_dht_put_immutable_item(alert_manager& alerts, sha1_hash target)
|
void on_dht_put_immutable_item(alert_manager& alerts, sha1_hash target, int num)
|
||||||
{
|
{
|
||||||
if (alerts.should_post<dht_put_alert>())
|
if (alerts.should_post<dht_put_alert>())
|
||||||
alerts.emplace_alert<dht_put_alert>(target);
|
alerts.emplace_alert<dht_put_alert>(target, num);
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_mutable_callback(alert_manager& alerts, dht::item& i
|
void on_dht_put_mutable_item(alert_manager& alerts, dht::item& i, int num)
|
||||||
|
{
|
||||||
|
boost::array<char, 64> sig = i.sig();
|
||||||
|
boost::array<char, 32> pk = i.pk();
|
||||||
|
boost::uint64_t 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_mutable_callback(dht::item& i
|
||||||
, boost::function<void(entry&, boost::array<char,64>&
|
, boost::function<void(entry&, boost::array<char,64>&
|
||||||
, boost::uint64_t&, std::string const&)> cb)
|
, boost::uint64_t&, std::string const&)> cb)
|
||||||
{
|
{
|
||||||
|
@ -5665,9 +5676,6 @@ retry:
|
||||||
std::string salt = i.salt();
|
std::string salt = i.salt();
|
||||||
cb(value, sig, seq, salt);
|
cb(value, sig, seq, salt);
|
||||||
i.assign(value, salt, seq, pk.data(), sig.data());
|
i.assign(value, salt, seq, pk.data(), sig.data());
|
||||||
|
|
||||||
if (alerts.should_post<dht_put_alert>())
|
|
||||||
alerts.emplace_alert<dht_put_alert>(pk, sig, salt, seq);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers)
|
void on_dht_get_peers(alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers)
|
||||||
|
@ -5690,7 +5698,7 @@ retry:
|
||||||
{
|
{
|
||||||
if (!m_dht) return;
|
if (!m_dht) return;
|
||||||
m_dht->put_item(data, boost::bind(&on_dht_put_immutable_item, boost::ref(m_alerts)
|
m_dht->put_item(data, boost::bind(&on_dht_put_immutable_item, boost::ref(m_alerts)
|
||||||
, target));
|
, target, _1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
||||||
|
@ -5699,8 +5707,9 @@ retry:
|
||||||
, std::string salt)
|
, std::string salt)
|
||||||
{
|
{
|
||||||
if (!m_dht) return;
|
if (!m_dht) return;
|
||||||
m_dht->put_item(key.data(), boost::bind(&put_mutable_callback
|
m_dht->put_item(key.data(),
|
||||||
, boost::ref(m_alerts), _1, cb), salt);
|
boost::bind(&on_dht_put_mutable_item, boost::ref(m_alerts), _1, _2),
|
||||||
|
boost::bind(&put_mutable_callback, _1, cb), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::dht_get_peers(sha1_hash const& info_hash)
|
void session_impl::dht_get_peers(sha1_hash const& info_hash)
|
||||||
|
|
|
@ -481,19 +481,37 @@ std::vector<dht::item> g_got_items;
|
||||||
dht::item g_put_item;
|
dht::item g_put_item;
|
||||||
int g_put_count;
|
int g_put_count;
|
||||||
|
|
||||||
bool get_item_cb(dht::item& i, bool a)
|
void get_mutable_item_cb(dht::item& i, bool a)
|
||||||
{
|
{
|
||||||
// only count authoritative data
|
if (!a) return;
|
||||||
if (!a) return false;
|
|
||||||
if (!i.empty())
|
if (!i.empty())
|
||||||
g_got_items.push_back(i);
|
g_got_items.push_back(i);
|
||||||
if (!g_put_item.empty())
|
}
|
||||||
{
|
|
||||||
i = g_put_item;
|
void put_mutable_item_data_cb(dht::item& i)
|
||||||
g_put_count++;
|
{
|
||||||
return true;
|
if (!i.empty())
|
||||||
}
|
g_got_items.push_back(i);
|
||||||
return false;
|
|
||||||
|
TEST_CHECK(!g_put_item.empty());
|
||||||
|
i = g_put_item;
|
||||||
|
g_put_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_mutable_item_cb(dht::item&, int num, int expect)
|
||||||
|
{
|
||||||
|
TEST_EQUAL(num, expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_immutable_item_cb(dht::item& i)
|
||||||
|
{
|
||||||
|
if (!i.empty())
|
||||||
|
g_got_items.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void put_immutable_item_cb(int num, int expect)
|
||||||
|
{
|
||||||
|
TEST_EQUAL(num, expect);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct obs : dht::dht_observer
|
struct obs : dht::dht_observer
|
||||||
|
@ -1633,7 +1651,7 @@ TORRENT_TEST(dht)
|
||||||
udp::endpoint initial_node(address_v4::from_string("4.4.4.4"), 1234);
|
udp::endpoint initial_node(address_v4::from_string("4.4.4.4"), 1234);
|
||||||
node.m_table.add_node(initial_node);
|
node.m_table.add_node(initial_node);
|
||||||
|
|
||||||
node.get_item(items[0].target, get_item_cb);
|
node.get_item(items[0].target, get_immutable_item_cb);
|
||||||
|
|
||||||
TEST_EQUAL(g_sent_packets.size(), 1);
|
TEST_EQUAL(g_sent_packets.size(), 1);
|
||||||
if (g_sent_packets.empty()) break;
|
if (g_sent_packets.empty()) break;
|
||||||
|
@ -1679,8 +1697,7 @@ TORRENT_TEST(dht)
|
||||||
udp::endpoint initial_node(address_v4::from_string("4.4.4.4"), 1234);
|
udp::endpoint initial_node(address_v4::from_string("4.4.4.4"), 1234);
|
||||||
node.m_table.add_node(initial_node);
|
node.m_table.add_node(initial_node);
|
||||||
|
|
||||||
sha1_hash target = hasher(public_key, item_pk_len).final();
|
node.get_item(public_key, std::string(), get_mutable_item_cb);
|
||||||
node.get_item(target, get_item_cb);
|
|
||||||
|
|
||||||
TEST_EQUAL(g_sent_packets.size(), 1);
|
TEST_EQUAL(g_sent_packets.size(), 1);
|
||||||
if (g_sent_packets.empty()) break;
|
if (g_sent_packets.empty()) break;
|
||||||
|
@ -1693,7 +1710,6 @@ TORRENT_TEST(dht)
|
||||||
{
|
{
|
||||||
TEST_EQUAL(parsed[0].string_value(), "q");
|
TEST_EQUAL(parsed[0].string_value(), "q");
|
||||||
TEST_EQUAL(parsed[2].string_value(), "get");
|
TEST_EQUAL(parsed[2].string_value(), "get");
|
||||||
TEST_EQUAL(parsed[5].string_value(), target.to_string());
|
|
||||||
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break;
|
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "get") break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1754,24 +1770,39 @@ TORRENT_TEST(dht)
|
||||||
|
|
||||||
// immutable put
|
// immutable put
|
||||||
g_sent_packets.clear();
|
g_sent_packets.clear();
|
||||||
do
|
for (int loop = 0; loop < 9; loop++)
|
||||||
{
|
{
|
||||||
|
// set the branching factor to k to make this a little easier
|
||||||
|
int old_branching = sett.search_branching;
|
||||||
|
sett.search_branching = 8;
|
||||||
dht::node node(&s, sett, (node_id::min)(), &observer, cnt);
|
dht::node node(&s, sett, (node_id::min)(), &observer, cnt);
|
||||||
enum { num_test_nodes = 2 };
|
enum { num_test_nodes = 8 };
|
||||||
node_entry nodes[num_test_nodes] =
|
node_entry nodes[num_test_nodes] =
|
||||||
{ node_entry(generate_next(), udp::endpoint(address_v4::from_string("4.4.4.4"), 1234))
|
{ node_entry(items[0].target, udp::endpoint(address_v4::from_string("1.1.1.1"), 1231))
|
||||||
, node_entry(generate_next(), udp::endpoint(address_v4::from_string("5.5.5.5"), 1235)) };
|
, node_entry(items[1].target, udp::endpoint(address_v4::from_string("2.2.2.2"), 1232))
|
||||||
|
, node_entry(items[2].target, udp::endpoint(address_v4::from_string("3.3.3.3"), 1233))
|
||||||
|
, node_entry(items[3].target, udp::endpoint(address_v4::from_string("4.4.4.4"), 1234))
|
||||||
|
, node_entry(items[4].target, udp::endpoint(address_v4::from_string("5.5.5.5"), 1235))
|
||||||
|
, node_entry(items[5].target, udp::endpoint(address_v4::from_string("6.6.6.6"), 1236))
|
||||||
|
, node_entry(items[6].target, udp::endpoint(address_v4::from_string("7.7.7.7"), 1237))
|
||||||
|
, node_entry(items[7].target, udp::endpoint(address_v4::from_string("8.8.8.8"), 1238)) };
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
for (int i = 0; i < num_test_nodes; ++i)
|
||||||
node.m_table.add_node(nodes[i]);
|
node.m_table.add_node(nodes[i]);
|
||||||
|
|
||||||
g_put_item.assign(items[0].ent);
|
entry put_data;
|
||||||
node.get_item(items[0].target, get_item_cb);
|
put_data = "Hello world";
|
||||||
|
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(), flat_data.size()));
|
||||||
|
|
||||||
TEST_EQUAL(g_sent_packets.size(), num_test_nodes);
|
node.put_item(target, put_data, boost::bind(&put_immutable_item_cb, _1, loop));
|
||||||
if (g_sent_packets.size() != num_test_nodes) break;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
TEST_EQUAL(g_sent_packets.size(), 8);
|
||||||
|
if (g_sent_packets.size() != 8) break;
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
||||||
TEST_CHECK(packet != g_sent_packets.end());
|
TEST_CHECK(packet != g_sent_packets.end());
|
||||||
|
@ -1788,18 +1819,19 @@ TORRENT_TEST(dht)
|
||||||
}
|
}
|
||||||
char t[10];
|
char t[10];
|
||||||
snprintf(t, sizeof(t), "%02d", i);
|
snprintf(t, sizeof(t), "%02d", i);
|
||||||
send_dht_response(node, response, nodes[i].ep()
|
|
||||||
, msg_args().token(t).port(1234).nid(nodes[i].id));
|
msg_args args;
|
||||||
|
args.token(t).port(1234).nid(nodes[i].id).nodes(nodes_t(1, nodes[i]));
|
||||||
|
send_dht_response(node, response, nodes[i].ep(), args);
|
||||||
g_sent_packets.erase(packet);
|
g_sent_packets.erase(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_EQUAL(g_put_count, 1);
|
TEST_EQUAL(g_sent_packets.size(), 8);
|
||||||
TEST_EQUAL(g_sent_packets.size(), num_test_nodes);
|
if (g_sent_packets.size() != 8) break;
|
||||||
if (g_sent_packets.size() != num_test_nodes) break;
|
|
||||||
|
|
||||||
itemv.second = bencode(buffer, items[0].ent);
|
itemv.second = bencode(buffer, put_data);
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
||||||
TEST_CHECK(packet != g_sent_packets.end());
|
TEST_CHECK(packet != g_sent_packets.end());
|
||||||
|
@ -1812,13 +1844,14 @@ TORRENT_TEST(dht)
|
||||||
{
|
{
|
||||||
TEST_EQUAL(parsed[0].string_value(), "q");
|
TEST_EQUAL(parsed[0].string_value(), "q");
|
||||||
TEST_EQUAL(parsed[2].string_value(), "put");
|
TEST_EQUAL(parsed[2].string_value(), "put");
|
||||||
std::pair<const char*, int> v = parsed[6].data_section();
|
std::pair<const char*, int>v = parsed[6].data_section();
|
||||||
TEST_EQUAL(v.second, itemv.second);
|
TEST_EQUAL(std::string(v.first, v.second), flat_data);
|
||||||
TEST_CHECK(memcmp(v.first, itemv.first, itemv.second) == 0);
|
|
||||||
char t[10];
|
char t[10];
|
||||||
snprintf(t, sizeof(t), "%02d", i);
|
snprintf(t, sizeof(t), "%02d", i);
|
||||||
TEST_EQUAL(parsed[5].string_value(), t);
|
TEST_EQUAL(parsed[5].string_value(), t);
|
||||||
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
|
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
|
||||||
|
|
||||||
|
if (i < loop) send_dht_response(node, response, nodes[i].ep());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1827,63 +1860,75 @@ TORRENT_TEST(dht)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sett.search_branching = old_branching;
|
||||||
g_sent_packets.clear();
|
g_sent_packets.clear();
|
||||||
g_put_item.clear();
|
g_put_item.clear();
|
||||||
g_put_count = 0;
|
g_put_count = 0;
|
||||||
|
|
||||||
} while (false);
|
};
|
||||||
|
|
||||||
// mutable put
|
// mutable put
|
||||||
g_sent_packets.clear();
|
g_sent_packets.clear();
|
||||||
do
|
for (int loop = 0; loop < 9; loop++)
|
||||||
{
|
{
|
||||||
|
// set the branching factor to k to make this a little easier
|
||||||
|
int old_branching = sett.search_branching;
|
||||||
|
sett.search_branching = 8;
|
||||||
dht::node node(&s, sett, (node_id::min)(), &observer, cnt);
|
dht::node node(&s, sett, (node_id::min)(), &observer, cnt);
|
||||||
enum { num_test_nodes = 2 };
|
enum { num_test_nodes = 8 };
|
||||||
node_entry nodes[num_test_nodes] =
|
node_entry nodes[num_test_nodes] =
|
||||||
{ node_entry(generate_next(), udp::endpoint(address_v4::from_string("4.4.4.4"), 1234))
|
{ node_entry(items[0].target, udp::endpoint(address_v4::from_string("1.1.1.1"), 1231))
|
||||||
, node_entry(generate_next(), udp::endpoint(address_v4::from_string("5.5.5.5"), 1235)) };
|
, node_entry(items[1].target, udp::endpoint(address_v4::from_string("2.2.2.2"), 1232))
|
||||||
|
, node_entry(items[2].target, udp::endpoint(address_v4::from_string("3.3.3.3"), 1233))
|
||||||
|
, node_entry(items[3].target, udp::endpoint(address_v4::from_string("4.4.4.4"), 1234))
|
||||||
|
, node_entry(items[4].target, udp::endpoint(address_v4::from_string("5.5.5.5"), 1235))
|
||||||
|
, node_entry(items[5].target, udp::endpoint(address_v4::from_string("6.6.6.6"), 1236))
|
||||||
|
, node_entry(items[6].target, udp::endpoint(address_v4::from_string("7.7.7.7"), 1237))
|
||||||
|
, node_entry(items[7].target, udp::endpoint(address_v4::from_string("8.8.8.8"), 1238)) };
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
for (int i = 0; i < num_test_nodes; ++i)
|
||||||
node.m_table.add_node(nodes[i]);
|
node.m_table.add_node(nodes[i]);
|
||||||
|
|
||||||
sha1_hash target = hasher(public_key, item_pk_len).final();
|
|
||||||
g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key);
|
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);
|
std::string sig(g_put_item.sig().data(), item_sig_len);
|
||||||
node.get_item(target, get_item_cb);
|
node.put_item(public_key, std::string()
|
||||||
|
, boost::bind(&put_mutable_item_cb, _1, _2, loop)
|
||||||
|
, put_mutable_item_data_cb);
|
||||||
|
|
||||||
TEST_EQUAL(g_sent_packets.size(), num_test_nodes);
|
TEST_EQUAL(g_sent_packets.size(), 8);
|
||||||
if (g_sent_packets.size() != num_test_nodes) break;
|
if (g_sent_packets.size() != 8) break;
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
||||||
TEST_CHECK(packet != g_sent_packets.end());
|
TEST_CHECK(packet != g_sent_packets.end());
|
||||||
if (packet == g_sent_packets.end()) continue;
|
if (packet == g_sent_packets.end()) continue;
|
||||||
|
|
||||||
lazy_from_entry(packet->second, response);
|
lazy_from_entry(packet->second, response);
|
||||||
ret = verify_message(response, get_item_desc, parsed, 6
|
ret = verify_message(response, get_item_desc, parsed, 6, error_string
|
||||||
, error_string, sizeof(error_string));
|
, sizeof(error_string));
|
||||||
if (!ret)
|
if (!ret)
|
||||||
{
|
{
|
||||||
fprintf(stderr, " invalid mutable put request: %s\n", print_entry(response).c_str());
|
fprintf(stderr, " invalid get request: %s\n", print_entry(response).c_str());
|
||||||
TEST_ERROR(error_string);
|
TEST_ERROR(error_string);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
char t[10];
|
char t[10];
|
||||||
snprintf(t, sizeof(t), "%02d", i);
|
snprintf(t, sizeof(t), "%02d", i);
|
||||||
send_dht_response(node, response, nodes[i].ep()
|
|
||||||
, msg_args().token(t).port(1234).nid(nodes[i].id));
|
msg_args args;
|
||||||
|
args.token(t).port(1234).nid(nodes[i].id).nodes(nodes_t(1, nodes[i]));
|
||||||
|
|
||||||
|
send_dht_response(node, response, nodes[i].ep(), args);
|
||||||
g_sent_packets.erase(packet);
|
g_sent_packets.erase(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_EQUAL(g_put_count, 1);
|
TEST_EQUAL(g_sent_packets.size(), 8);
|
||||||
TEST_EQUAL(g_sent_packets.size(), num_test_nodes);
|
if (g_sent_packets.size() != 8) break;
|
||||||
if (g_sent_packets.size() != num_test_nodes) break;
|
|
||||||
|
|
||||||
itemv.second = bencode(buffer, items[0].ent);
|
itemv.second = bencode(buffer, items[0].ent);
|
||||||
|
|
||||||
for (int i = 0; i < num_test_nodes; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
std::list<std::pair<udp::endpoint, entry> >::iterator packet = find_packet(nodes[i].ep());
|
||||||
TEST_CHECK(packet != g_sent_packets.end());
|
TEST_CHECK(packet != g_sent_packets.end());
|
||||||
|
@ -1906,6 +1951,8 @@ TORRENT_TEST(dht)
|
||||||
snprintf(t, sizeof(t), "%02d", i);
|
snprintf(t, sizeof(t), "%02d", i);
|
||||||
TEST_EQUAL(parsed[9].string_value(), t);
|
TEST_EQUAL(parsed[9].string_value(), t);
|
||||||
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
|
if (parsed[0].string_value() != "q" || parsed[2].string_value() != "put") continue;
|
||||||
|
|
||||||
|
if (i < loop) send_dht_response(node, response, nodes[i].ep());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1914,12 +1961,11 @@ TORRENT_TEST(dht)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
sett.search_branching = old_branching;
|
||||||
g_sent_packets.clear();
|
g_sent_packets.clear();
|
||||||
g_put_item.clear();
|
g_put_item.clear();
|
||||||
g_put_count = 0;
|
g_put_count = 0;
|
||||||
|
}
|
||||||
} while (false);
|
|
||||||
|
|
||||||
// verify that done() is only invoked once
|
// verify that done() is only invoked once
|
||||||
// See PR 252
|
// See PR 252
|
||||||
|
@ -1952,10 +1998,11 @@ TORRENT_TEST(dht)
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
node.m_table.add_node(nodes[i]);
|
node.m_table.add_node(nodes[i]);
|
||||||
|
|
||||||
// kick off a mutable get request
|
// kick off a mutable put request
|
||||||
g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key);
|
g_put_item.assign(items[0].ent, empty_salt, seq, public_key, private_key);
|
||||||
node.get_item(target, get_item_cb);
|
node.put_item(public_key, std::string()
|
||||||
|
, boost::bind(&put_mutable_item_cb, _1, _2, 0)
|
||||||
|
, put_mutable_item_data_cb);
|
||||||
TEST_EQUAL(g_sent_packets.size(), 8);
|
TEST_EQUAL(g_sent_packets.size(), 8);
|
||||||
if (g_sent_packets.size() != 8) break;
|
if (g_sent_packets.size() != 8) break;
|
||||||
|
|
||||||
|
@ -2308,7 +2355,7 @@ TORRENT_TEST(read_only_node)
|
||||||
bdecode_node request;
|
bdecode_node request;
|
||||||
sha1_hash target = generate_next();
|
sha1_hash target = generate_next();
|
||||||
|
|
||||||
node.get_item(target, get_item_cb);
|
node.get_item(target, get_immutable_item_cb);
|
||||||
TEST_EQUAL(g_sent_packets.size(), 1);
|
TEST_EQUAL(g_sent_packets.size(), 1);
|
||||||
TEST_EQUAL(g_sent_packets.front().first, initial_node);
|
TEST_EQUAL(g_sent_packets.front().first, initial_node);
|
||||||
|
|
||||||
|
@ -2342,7 +2389,7 @@ TORRENT_TEST(read_only_node)
|
||||||
|
|
||||||
g_sent_packets.clear();
|
g_sent_packets.clear();
|
||||||
target = generate_next();
|
target = generate_next();
|
||||||
node.get_item(target, get_item_cb);
|
node.get_item(target, get_immutable_item_cb);
|
||||||
|
|
||||||
// since we have 2 nodes, we should have two packets.
|
// since we have 2 nodes, we should have two packets.
|
||||||
TEST_EQUAL(g_sent_packets.size(), 2);
|
TEST_EQUAL(g_sent_packets.size(), 2);
|
||||||
|
|
|
@ -320,7 +320,9 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
printf("PUT %s\n", to_hex(target.to_string()).c_str());
|
printf("PUT %s\n", to_hex(target.to_string()).c_str());
|
||||||
|
|
||||||
wait_for_alert(s, dht_put_alert::alert_type);
|
alert* a = wait_for_alert(s, dht_put_alert::alert_type);
|
||||||
|
dht_put_alert* pa = alert_cast<dht_put_alert>(a);
|
||||||
|
printf("%s\n", pa->message().c_str());
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[0], "mput") == 0)
|
else if (strcmp(argv[0], "mput") == 0)
|
||||||
{
|
{
|
||||||
|
@ -353,10 +355,12 @@ int main(int argc, char* argv[])
|
||||||
s.dht_put_item(public_key, boost::bind(&put_string, _1, _2, _3, _4
|
s.dht_put_item(public_key, boost::bind(&put_string, _1, _2, _3, _4
|
||||||
, public_key.data(), private_key.data(), argv[0]));
|
, public_key.data(), private_key.data(), argv[0]));
|
||||||
|
|
||||||
printf("public key: %s\n", to_hex(std::string(public_key.data()
|
printf("MPUT publick key: %s\n", to_hex(std::string(public_key.data()
|
||||||
, public_key.size())).c_str());
|
, public_key.size())).c_str());
|
||||||
|
|
||||||
wait_for_alert(s, dht_put_alert::alert_type);
|
alert* a = wait_for_alert(s, dht_put_alert::alert_type);
|
||||||
|
dht_put_alert* pa = alert_cast<dht_put_alert>(a);
|
||||||
|
printf("%s\n", pa->message().c_str());
|
||||||
}
|
}
|
||||||
else if (strcmp(argv[0], "mget") == 0)
|
else if (strcmp(argv[0], "mget") == 0)
|
||||||
{
|
{
|
||||||
|
@ -380,6 +384,7 @@ int main(int argc, char* argv[])
|
||||||
|
|
||||||
bootstrap(s);
|
bootstrap(s);
|
||||||
s.dht_get_item(public_key);
|
s.dht_get_item(public_key);
|
||||||
|
printf("MGET %s\n", argv[0]);
|
||||||
|
|
||||||
bool authoritative = false;
|
bool authoritative = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue