Miguel Freitas
12 years ago
8 changed files with 485 additions and 1 deletions
@ -0,0 +1,117 @@
@@ -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 @@
@@ -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