diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 5b1777396..70df1de84 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -1993,7 +1993,8 @@ namespace libtorrent , boost::array sig , boost::uint64_t sequence , std::string const& s - , entry const& i); + , entry const& i + , bool a); TORRENT_DEFINE_ALERT_PRIO(dht_mutable_item_alert, 75) @@ -2022,6 +2023,9 @@ namespace libtorrent // the data for this item entry item; + + // the last response for mutable date is authoritative. + bool authoritative; }; // this is posted when a DHT put operation completes. This is useful if the diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index a55e6208c..21272b2c6 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -300,7 +300,7 @@ namespace libtorrent void get_immutable_callback(sha1_hash target , dht::item const& i); - void get_mutable_callback(dht::item const& i); + void get_mutable_callback(dht::item const& i, bool); void dht_get_immutable_item(sha1_hash const& target); diff --git a/include/libtorrent/kademlia/dht_tracker.hpp b/include/libtorrent/kademlia/dht_tracker.hpp index 0a2dc4b2b..dd30a36db 100644 --- a/include/libtorrent/kademlia/dht_tracker.hpp +++ b/include/libtorrent/kademlia/dht_tracker.hpp @@ -97,7 +97,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 - , boost::function cb + , boost::function cb , std::string salt = std::string()); void put_item(entry data diff --git a/include/libtorrent/kademlia/get_item.hpp b/include/libtorrent/kademlia/get_item.hpp index 399769260..3a52b6c9c 100644 --- a/include/libtorrent/kademlia/get_item.hpp +++ b/include/libtorrent/kademlia/get_item.hpp @@ -43,7 +43,7 @@ namespace libtorrent { namespace dht class get_item : public find_data { public: - typedef boost::function data_callback; + typedef boost::function data_callback; void got_data(bdecode_node const& v, char const* pk, diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index 22dae4b9d..0d7136a84 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -245,8 +245,8 @@ public: void announce(sha1_hash const& info_hash, int listen_port, int flags , boost::function const&)> f); - void get_item(sha1_hash const& target, boost::function f); - void get_item(char const* pk, std::string const& salt, boost::function f); + void get_item(sha1_hash const& target, boost::function f); + void get_item(char const* pk, std::string const& salt, boost::function f); bool verify_token(std::string const& token, char const* info_hash , udp::endpoint const& addr); diff --git a/src/alert.cpp b/src/alert.cpp index 5c910ede7..aa9b8f268 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -1448,17 +1448,19 @@ namespace libtorrent { , boost::array sig , boost::uint64_t sequence , std::string const& s - , entry const& i) - : key(k), signature(sig), seq(sequence), salt(s), item(i) + , entry const& i + , bool a) + : key(k), signature(sig), seq(sequence), salt(s), item(i), authoritative(a) {} std::string dht_mutable_item_alert::message() const { char msg[1050]; - snprintf(msg, sizeof(msg), "DHT mutable item (key=%s salt=%s seq=%" PRId64 ") [ %s ]" + snprintf(msg, sizeof(msg), "DHT mutable item (key=%s salt=%s seq=%" PRId64 " %s) [ %s ]" , to_hex(std::string(&key[0], 32)).c_str() , salt.c_str() , seq + , authoritative ? "auth" : "non-auth" , item.to_string().c_str()); return msg; } diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index 514141fa8..008f9807f 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -247,12 +247,12 @@ namespace libtorrent { namespace dht return false; } - bool get_mutable_item_callback(item& it, boost::function f) + bool get_mutable_item_callback(item& it, bool authoritative, boost::function 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); + f(it, authoritative); return false; } @@ -267,9 +267,11 @@ namespace libtorrent { namespace dht return true; } - bool put_mutable_item_callback(item& it, boost::function cb) + bool put_mutable_item_callback(item& it, bool authoritative, boost::function cb) { - cb(it); + if (authoritative) { + cb(it); + } return true; } @@ -284,10 +286,10 @@ 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 - , boost::function cb + , boost::function cb , std::string salt) { - m_dht.get_item(key, salt, boost::bind(&get_mutable_item_callback, _1, cb)); + m_dht.get_item(key, salt, boost::bind(&get_mutable_item_callback, _1, _2, cb)); } void dht_tracker::put_item(entry data @@ -306,7 +308,7 @@ namespace libtorrent { namespace dht , boost::function cb, std::string salt) { m_dht.get_item(key, salt, boost::bind(&put_mutable_item_callback - , _1, cb)); + , _1, _2, cb)); } // translate bittorrent kademlia message into the generice kademlia message diff --git a/src/kademlia/get_item.cpp b/src/kademlia/get_item.cpp index e2d892272..74b28725d 100644 --- a/src/kademlia/get_item.cpp +++ b/src/kademlia/get_item.cpp @@ -70,6 +70,16 @@ void get_item::got_data(bdecode_node const& v, { 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. + // 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()) @@ -78,7 +88,7 @@ void get_item::got_data(bdecode_node const& v, // and it's immutable m_data.assign(v); - bool put_requested = m_data_callback(m_data); + bool put_requested = m_data_callback(m_data, true); // if we intend to put, we need to keep going // until we find the closest nodes, since those @@ -162,10 +172,10 @@ void get_item::done() { if (m_data.is_mutable() || m_data.empty()) { - // for mutable data, we only call the callback at the end, - // when we've heard from everyone, to be sure we got the + // for mutable data, now we have authoritative data since + // we've heard from everyone, to be sure we got the // latest version of the data (i.e. highest sequence number) - bool put_requested = m_data_callback(m_data); + bool put_requested = m_data_callback(m_data, true); if (put_requested) { #if TORRENT_USE_ASSERTS diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index e906b2334..84a030589 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -412,7 +412,7 @@ void node::announce(sha1_hash const& info_hash, int listen_port, int flags } void node::get_item(sha1_hash const& target - , boost::function f) + , boost::function f) { #ifndef TORRENT_DISABLE_LOGGING if (m_observer) @@ -430,7 +430,7 @@ void node::get_item(sha1_hash const& target } void node::get_item(char const* pk, std::string const& salt - , boost::function f) + , boost::function f) { #ifndef TORRENT_DISABLE_LOGGING if (m_observer) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 9009b3a04..b1a4005fb 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -5485,11 +5485,11 @@ retry: } // callback for dht_mutable_get - void session_impl::get_mutable_callback(dht::item const& i) + void session_impl::get_mutable_callback(dht::item const& i, bool authoritative) { TORRENT_ASSERT(i.is_mutable()); m_alerts.emplace_alert(i.pk(), i.sig(), i.seq() - , i.salt(), i.value()); + , i.salt(), i.value(), authoritative); } // key is a 32-byte binary string, the public key to look up. @@ -5499,7 +5499,7 @@ retry: { if (!m_dht) return; m_dht->get_item(key.data(), boost::bind(&session_impl::get_mutable_callback - , this, _1), salt); + , this, _1, _2), salt); } namespace { diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 3a245e865..f256bddcc 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -406,7 +406,7 @@ std::vector g_got_items; dht::item g_put_item; int g_put_count; -bool get_item_cb(dht::item& i) +bool get_item_cb(dht::item& i, bool a) { if (!i.empty()) g_got_items.push_back(i);