Miguel Freitas
11 years ago
8 changed files with 485 additions and 1 deletions
@ -0,0 +1,117 @@ |
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2006-2012, 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. |
||||||
|
|
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef DHT_GET_050323_HPP |
||||||
|
#define DHT_GET_050323_HPP |
||||||
|
|
||||||
|
#include <vector> |
||||||
|
#include <map> |
||||||
|
|
||||||
|
#include <libtorrent/kademlia/traversal_algorithm.hpp> |
||||||
|
#include <libtorrent/kademlia/node_id.hpp> |
||||||
|
#include <libtorrent/kademlia/routing_table.hpp> |
||||||
|
#include <libtorrent/kademlia/rpc_manager.hpp> |
||||||
|
#include <libtorrent/kademlia/observer.hpp> |
||||||
|
#include <libtorrent/kademlia/msg.hpp> |
||||||
|
|
||||||
|
#include <boost/optional.hpp> |
||||||
|
#include <boost/function/function1.hpp> |
||||||
|
#include <boost/function/function2.hpp> |
||||||
|
|
||||||
|
namespace libtorrent { namespace dht |
||||||
|
{ |
||||||
|
|
||||||
|
typedef std::vector<char> packet_t; |
||||||
|
|
||||||
|
class rpc_manager; |
||||||
|
class node_impl; |
||||||
|
|
||||||
|
// -------- dht get -----------
|
||||||
|
|
||||||
|
class dht_get : public traversal_algorithm |
||||||
|
{ |
||||||
|
public: |
||||||
|
// callback to receive data from "get"
|
||||||
|
typedef boost::function<void(entry::list_type const&)> data_callback; |
||||||
|
|
||||||
|
// callback to receive all write tokens
|
||||||
|
typedef boost::function<void(std::vector<std::pair<node_entry, std::string> > const&, bool)> nodes_callback; |
||||||
|
|
||||||
|
void got_data(entry::list_type const& values_list); |
||||||
|
void got_write_token(node_id const& n, std::string const& write_token) |
||||||
|
{ m_write_tokens[n] = write_token; } |
||||||
|
|
||||||
|
dht_get(node_impl& node |
||||||
|
, std::string &targetUser, std::string &targetResource, bool multi |
||||||
|
, data_callback const& dcallback |
||||||
|
, nodes_callback const& ncallback |
||||||
|
, bool justToken); |
||||||
|
|
||||||
|
virtual char const* name() const { return "getData"; } |
||||||
|
|
||||||
|
node_id const target() const { return traversal_algorithm::target(); } |
||||||
|
|
||||||
|
protected: |
||||||
|
|
||||||
|
void done(); |
||||||
|
observer_ptr new_observer(void* ptr, udp::endpoint const& ep, node_id const& id); |
||||||
|
virtual bool invoke(observer_ptr o); |
||||||
|
|
||||||
|
private: |
||||||
|
|
||||||
|
data_callback m_data_callback; |
||||||
|
nodes_callback m_nodes_callback; |
||||||
|
std::map<node_id, std::string> m_write_tokens; |
||||||
|
entry::dictionary_type m_target; |
||||||
|
std::string const m_targetUser; |
||||||
|
std::string const m_targetResource; |
||||||
|
bool m_multi:1; |
||||||
|
bool m_done:1; |
||||||
|
bool m_got_data:1; |
||||||
|
bool m_justToken:1; |
||||||
|
}; |
||||||
|
|
||||||
|
class dht_get_observer : public observer |
||||||
|
{ |
||||||
|
public: |
||||||
|
dht_get_observer( |
||||||
|
boost::intrusive_ptr<traversal_algorithm> const& algorithm |
||||||
|
, udp::endpoint const& ep, node_id const& id) |
||||||
|
: observer(algorithm, ep, id) |
||||||
|
{} |
||||||
|
void reply(msg const&); |
||||||
|
}; |
||||||
|
|
||||||
|
} } // namespace libtorrent::dht
|
||||||
|
|
||||||
|
#endif // DHT_GET_050323_HPP
|
||||||
|
|
@ -0,0 +1,278 @@ |
|||||||
|
/*
|
||||||
|
|
||||||
|
Copyright (c) 2006-2012, 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 "../../src/twister.h" |
||||||
|
|
||||||
|
#include "libtorrent/pch.hpp" |
||||||
|
|
||||||
|
#include <libtorrent/kademlia/dht_get.hpp> |
||||||
|
#include <libtorrent/kademlia/routing_table.hpp> |
||||||
|
#include <libtorrent/kademlia/rpc_manager.hpp> |
||||||
|
#include <libtorrent/kademlia/node.hpp> |
||||||
|
#include <libtorrent/io.hpp> |
||||||
|
#include <libtorrent/socket.hpp> |
||||||
|
#include <libtorrent/socket_io.hpp> |
||||||
|
#include <libtorrent/bencode.hpp> |
||||||
|
#include <libtorrent/hasher.hpp> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
namespace libtorrent { namespace dht |
||||||
|
{ |
||||||
|
|
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_DECLARE_LOG(traversal); |
||||||
|
#endif |
||||||
|
|
||||||
|
using detail::read_endpoint_list; |
||||||
|
using detail::read_v4_endpoint; |
||||||
|
#if TORRENT_USE_IPV6 |
||||||
|
using detail::read_v6_endpoint; |
||||||
|
#endif |
||||||
|
|
||||||
|
void dht_get_observer::reply(msg const& m) |
||||||
|
{ |
||||||
|
lazy_entry const* r = m.message.dict_find_dict("r"); |
||||||
|
if (!r) |
||||||
|
{ |
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] missing response dict"; |
||||||
|
#endif |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
lazy_entry const* id = r->dict_find_string("id"); |
||||||
|
if (!id || id->string_length() != 20) |
||||||
|
{ |
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_LOG(traversal) << "[" << m_algorithm.get() << "] invalid id in response"; |
||||||
|
#endif |
||||||
|
return; |
||||||
|
} |
||||||
|
lazy_entry const* token = r->dict_find_string("token"); |
||||||
|
if (token) |
||||||
|
{ |
||||||
|
static_cast<dht_get*>(m_algorithm.get())->got_write_token( |
||||||
|
node_id(id->string_ptr()), token->string_value()); |
||||||
|
} |
||||||
|
|
||||||
|
// look for peers
|
||||||
|
lazy_entry const* n = r->dict_find_list("values"); |
||||||
|
if (n) |
||||||
|
{ |
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_LOG(traversal) |
||||||
|
<< "[" << m_algorithm.get() << "] GETDATA" |
||||||
|
<< " invoke-count: " << m_algorithm->invoke_count() |
||||||
|
<< " branch-factor: " << m_algorithm->branch_factor() |
||||||
|
<< " addr: " << m.addr |
||||||
|
<< " id: " << node_id(id->string_ptr()) |
||||||
|
<< " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr())) |
||||||
|
<< " p: " << ((end - peers) / 6); |
||||||
|
#endif |
||||||
|
entry::list_type values_list; |
||||||
|
for (int i = 0; i < n->list_size(); ++i) |
||||||
|
{ |
||||||
|
lazy_entry const* e = n->list_at(i); |
||||||
|
if (e->type() != lazy_entry::dict_t) continue; |
||||||
|
|
||||||
|
lazy_entry const* p = e->dict_find("p"); |
||||||
|
lazy_entry const* sig_p = e->dict_find("sig_p"); |
||||||
|
lazy_entry const* sig_user = e->dict_find("sig_user"); |
||||||
|
if (!p || !sig_p || !sig_user) continue; |
||||||
|
if (p->type() != lazy_entry::dict_t) continue; |
||||||
|
if (sig_p->type() != lazy_entry::string_t) continue; |
||||||
|
if (sig_user->type() != lazy_entry::string_t) continue; |
||||||
|
|
||||||
|
std::pair<char const*, int> buf = p->data_section(); |
||||||
|
if (!verifySignature(std::string(buf.first,buf.second), |
||||||
|
sig_user->string_value(), |
||||||
|
sig_p->string_value())) { |
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_LOG(traversal) << "dht_get_observer::reply verifySignature failed"; |
||||||
|
#endif |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
values_list.push_back(entry()); |
||||||
|
values_list.back() = *e; |
||||||
|
} |
||||||
|
|
||||||
|
static_cast<dht_get*>(m_algorithm.get())->got_data(values_list); |
||||||
|
} |
||||||
|
|
||||||
|
// look for nodes
|
||||||
|
n = r->dict_find_string("nodes"); |
||||||
|
if (n) |
||||||
|
{ |
||||||
|
std::vector<node_entry> node_list; |
||||||
|
char const* nodes = n->string_ptr(); |
||||||
|
char const* end = nodes + n->string_length(); |
||||||
|
|
||||||
|
while (end - nodes >= 26) |
||||||
|
{ |
||||||
|
node_id id; |
||||||
|
std::copy(nodes, nodes + 20, id.begin()); |
||||||
|
nodes += 20; |
||||||
|
m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(nodes)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
n = r->dict_find_list("nodes2"); |
||||||
|
if (n) |
||||||
|
{ |
||||||
|
for (int i = 0; i < n->list_size(); ++i) |
||||||
|
{ |
||||||
|
lazy_entry const* p = n->list_at(0); |
||||||
|
if (p->type() != lazy_entry::string_t) continue; |
||||||
|
if (p->string_length() < 6 + 20) continue; |
||||||
|
char const* in = p->string_ptr(); |
||||||
|
|
||||||
|
node_id id; |
||||||
|
std::copy(in, in + 20, id.begin()); |
||||||
|
in += 20; |
||||||
|
if (p->string_length() == 6 + 20) |
||||||
|
m_algorithm->traverse(id, read_v4_endpoint<udp::endpoint>(in)); |
||||||
|
#if TORRENT_USE_IPV6 |
||||||
|
else if (p->string_length() == 18 + 20) |
||||||
|
m_algorithm->traverse(id, read_v6_endpoint<udp::endpoint>(in)); |
||||||
|
#endif |
||||||
|
} |
||||||
|
} |
||||||
|
done(); |
||||||
|
} |
||||||
|
|
||||||
|
static void add_entry_fun(void* userdata, node_entry const& e) |
||||||
|
{ |
||||||
|
traversal_algorithm* f = (traversal_algorithm*)userdata; |
||||||
|
f->add_entry(e.id, e.ep(), observer::flag_initial); |
||||||
|
} |
||||||
|
|
||||||
|
dht_get::dht_get( |
||||||
|
node_impl& node |
||||||
|
, std::string &targetUser |
||||||
|
, std::string &targetResource |
||||||
|
, bool multi |
||||||
|
, data_callback const& dcallback |
||||||
|
, nodes_callback const& ncallback |
||||||
|
, bool justToken) |
||||||
|
: traversal_algorithm(node, node_id()) |
||||||
|
, m_data_callback(dcallback) |
||||||
|
, m_nodes_callback(ncallback) |
||||||
|
, m_target() |
||||||
|
, m_targetUser(targetUser) |
||||||
|
, m_targetResource(targetResource) |
||||||
|
, m_multi(multi) |
||||||
|
, m_done(false) |
||||||
|
, m_got_data(false) |
||||||
|
, m_justToken(justToken) |
||||||
|
{ |
||||||
|
m_target["n"] = m_targetUser; |
||||||
|
m_target["r"] = m_targetResource; |
||||||
|
m_target["t"] = (m_multi) ? "m" : "s"; |
||||||
|
|
||||||
|
std::vector<char> buf; |
||||||
|
bencode(std::back_inserter(buf), m_target); |
||||||
|
sha1_hash target; |
||||||
|
target = hasher(buf.data(), buf.size()).final(); |
||||||
|
set_target(target); |
||||||
|
|
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
//TORRENT_LOG(traversal) << "[" << this << "] NEW"
|
||||||
|
// " target: " << target << " k: " << m_node.m_table.bucket_size();
|
||||||
|
#endif |
||||||
|
node.m_table.for_each_node(&add_entry_fun, 0, (traversal_algorithm*)this); |
||||||
|
} |
||||||
|
|
||||||
|
observer_ptr dht_get::new_observer(void* ptr |
||||||
|
, udp::endpoint const& ep, node_id const& id) |
||||||
|
{ |
||||||
|
observer_ptr o(new (ptr) dht_get_observer(this, ep, id)); |
||||||
|
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS |
||||||
|
o->m_in_constructor = false; |
||||||
|
#endif |
||||||
|
return o; |
||||||
|
} |
||||||
|
|
||||||
|
bool dht_get::invoke(observer_ptr o) |
||||||
|
{ |
||||||
|
if (m_done) |
||||||
|
{ |
||||||
|
m_invoke_count = -1; |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
entry e; |
||||||
|
e["z"] = "q"; |
||||||
|
e["q"] = "getData"; |
||||||
|
entry& a = e["x"]; |
||||||
|
entry& target = a["target"]; |
||||||
|
target = m_target; |
||||||
|
if (m_justToken) a["justtoken"] = 1; |
||||||
|
return m_node.m_rpc.invoke(e, o->target_ep(), o); |
||||||
|
} |
||||||
|
|
||||||
|
void dht_get::got_data(entry::list_type const& values_list) |
||||||
|
{ |
||||||
|
if (!values_list.empty()) m_got_data = true; |
||||||
|
m_data_callback(values_list); |
||||||
|
} |
||||||
|
|
||||||
|
void dht_get::done() |
||||||
|
{ |
||||||
|
if (m_invoke_count != 0) return; |
||||||
|
|
||||||
|
m_done = true; |
||||||
|
|
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING |
||||||
|
TORRENT_LOG(traversal) << "[" << this << "] getData DONE"; |
||||||
|
#endif |
||||||
|
|
||||||
|
std::vector<std::pair<node_entry, std::string> > results; |
||||||
|
int num_results = m_node.m_table.bucket_size(); |
||||||
|
for (std::vector<observer_ptr>::iterator i = m_results.begin() |
||||||
|
, end(m_results.end()); i != end && num_results > 0; ++i) |
||||||
|
{ |
||||||
|
observer_ptr const& o = *i; |
||||||
|
if (o->flags & observer::flag_no_id) continue; |
||||||
|
if ((o->flags & observer::flag_queried) == 0) continue; |
||||||
|
std::map<node_id, std::string>::iterator j = m_write_tokens.find(o->id()); |
||||||
|
if (j == m_write_tokens.end()) continue; |
||||||
|
results.push_back(std::make_pair(node_entry(o->id(), o->target_ep()), j->second)); |
||||||
|
--num_results; |
||||||
|
} |
||||||
|
m_nodes_callback(results, m_got_data); |
||||||
|
|
||||||
|
traversal_algorithm::done(); |
||||||
|
} |
||||||
|
|
||||||
|
} } // namespace libtorrent::dht
|
||||||
|
|
Loading…
Reference in new issue