forked from premiere/premiere-libtorrent
fix dht_bootstrap_alert being posted. add additional alert for dht put completion. add utility to test immutable put/get. fix issue in DHT preventing stores on router nodes (even when they return write tokens). immutable put and get confirmed to be working
This commit is contained in:
parent
1188ec2dcd
commit
86c704a6ff
|
@ -7,7 +7,7 @@
|
|||
* allow force_announce to only affect a single tracker
|
||||
* add moving_storage field to torrent_status
|
||||
* expose UPnP and NAT-PMP mapping in session object
|
||||
* DHT refactoring and support for storing arbitrary data with put
|
||||
* DHT refactoring and support for storing arbitrary data with put and get
|
||||
* support building on android
|
||||
* improved support for web seeds that don't support keep-alive
|
||||
* improve DHT routing table to return better nodes (lower RTT and closer
|
||||
|
@ -41,6 +41,7 @@
|
|||
* fix uTP edge case where udp socket buffer fills up
|
||||
* fix nagle implementation in uTP
|
||||
|
||||
* fix dht_bootstrap_alert being posted
|
||||
* SetFileValidData fix on windows (prevents zero-fill)
|
||||
* fix minor lock_files issue on unix
|
||||
|
||||
|
|
|
@ -1520,8 +1520,8 @@ namespace libtorrent
|
|||
int reason;
|
||||
};
|
||||
|
||||
// This alert is generated when a DHT node announces to an info-hash on our DHT node. It belongs
|
||||
// to the ``dht_notification`` category.
|
||||
// This alert is generated when a DHT node announces to an info-hash on our
|
||||
// DHT node. It belongs to the ``dht_notification`` category.
|
||||
struct TORRENT_EXPORT dht_announce_alert: alert
|
||||
{
|
||||
// internal
|
||||
|
@ -1542,8 +1542,8 @@ namespace libtorrent
|
|||
sha1_hash info_hash;
|
||||
};
|
||||
|
||||
// This alert is generated when a DHT node sends a ``get_peers`` message to our DHT node.
|
||||
// It belongs to the ``dht_notification`` category.
|
||||
// This alert is generated when a DHT node sends a ``get_peers`` message to
|
||||
// our DHT node. It belongs to the ``dht_notification`` category.
|
||||
struct TORRENT_EXPORT dht_get_peers_alert: alert
|
||||
{
|
||||
// internal
|
||||
|
@ -1590,21 +1590,22 @@ namespace libtorrent
|
|||
num_channels
|
||||
};
|
||||
|
||||
// an array of samples. The enum describes what each
|
||||
// sample is a measurement of. All of these are raw, and not smoothing is performed.
|
||||
// an array of samples. The enum describes what each sample is a
|
||||
// measurement of. All of these are raw, and not smoothing is performed.
|
||||
int transferred[num_channels];
|
||||
|
||||
// the number of milliseconds during which these stats
|
||||
// were collected. This is typically just above 1000, but if CPU is
|
||||
// limited, it may be higher than that.
|
||||
// the number of milliseconds during which these stats were collected.
|
||||
// This is typically just above 1000, but if CPU is limited, it may be
|
||||
// higher than that.
|
||||
int interval;
|
||||
};
|
||||
|
||||
// This alert is posted when the disk cache has been flushed for a specific torrent
|
||||
// as a result of a call to torrent_handle::flush_cache(). This alert belongs to the
|
||||
// ``storage_notification`` category, which must be enabled to let this alert through.
|
||||
// The alert is also posted when removing a torrent from the session, once the outstanding
|
||||
// cache flush is complete and the torrent does no longer have any files open.
|
||||
// This alert is posted when the disk cache has been flushed for a specific
|
||||
// torrent as a result of a call to torrent_handle::flush_cache(). This
|
||||
// alert belongs to the ``storage_notification`` category, which must be
|
||||
// enabled to let this alert through. The alert is also posted when removing
|
||||
// a torrent from the session, once the outstanding cache flush is complete
|
||||
// and the torrent does no longer have any files open.
|
||||
struct TORRENT_EXPORT cache_flushed_alert: torrent_alert
|
||||
{
|
||||
// internal
|
||||
|
@ -1647,8 +1648,8 @@ namespace libtorrent
|
|||
std::string str;
|
||||
};
|
||||
|
||||
// This alert is generated when we receive a local service discovery message from a peer
|
||||
// for a torrent we're currently participating in.
|
||||
// This alert is generated when we receive a local service discovery message
|
||||
// from a peer for a torrent we're currently participating in.
|
||||
struct TORRENT_EXPORT lsd_peer_alert: peer_alert
|
||||
{
|
||||
// internal
|
||||
|
@ -1663,9 +1664,9 @@ namespace libtorrent
|
|||
virtual std::string message() const;
|
||||
};
|
||||
|
||||
// This alert is posted whenever a tracker responds with a ``trackerid``. The tracker ID
|
||||
// is like a cookie. The libtorrent will store the tracker ID for this tracker and
|
||||
// repeat it in subsequent announces.
|
||||
// This alert is posted whenever a tracker responds with a ``trackerid``.
|
||||
// The tracker ID is like a cookie. The libtorrent will store the tracker ID
|
||||
// for this tracker and repeat it in subsequent announces.
|
||||
struct TORRENT_EXPORT trackerid_alert: tracker_alert
|
||||
{
|
||||
// internal
|
||||
|
@ -2003,6 +2004,43 @@ namespace libtorrent
|
|||
// the data for this item
|
||||
entry item;
|
||||
};
|
||||
|
||||
// this is posted when a DHT put operation completes. This is useful if the
|
||||
// client is waiting for a put to complete before shutting down for instance.
|
||||
struct TORRENT_EXPORT dht_put_alert: alert
|
||||
{
|
||||
// internal
|
||||
dht_put_alert(sha1_hash const& t)
|
||||
: target(t)
|
||||
, seq(0)
|
||||
{}
|
||||
dht_put_alert(boost::array<char, 32> key
|
||||
, boost::array<char, 64> sig
|
||||
, std::string s
|
||||
, uint64_t sequence_number)
|
||||
: target(0)
|
||||
, public_key(key)
|
||||
, signature(sig)
|
||||
, salt(s)
|
||||
, seq(sequence_number)
|
||||
{}
|
||||
|
||||
TORRENT_DEFINE_ALERT(dht_put_alert);
|
||||
|
||||
const static int static_category = alert::dht_notification;
|
||||
virtual std::string message() const;
|
||||
|
||||
// the target hash the item was stored under if this was an *immutable*
|
||||
// item.
|
||||
sha1_hash target;
|
||||
|
||||
// if a mutable item was stored, these are the public key, signature,
|
||||
// salt and sequence number the item was stored under.
|
||||
boost::array<char, 32> public_key;
|
||||
boost::array<char, 64> signature;
|
||||
std::string salt;
|
||||
boost::uint64_t seq;
|
||||
};
|
||||
#undef TORRENT_DEFINE_ALERT
|
||||
|
||||
}
|
||||
|
|
|
@ -323,7 +323,7 @@ namespace libtorrent
|
|||
void dht_get_mutable_item(boost::array<char, 32> key
|
||||
, std::string salt = std::string());
|
||||
|
||||
void dht_put_item(entry data);
|
||||
void dht_put_item(entry data, sha1_hash target);
|
||||
|
||||
void dht_put_mutable_item(boost::array<char, 32> key
|
||||
, boost::function<void(entry&, boost::array<char,64>&
|
||||
|
|
|
@ -149,16 +149,18 @@ namespace libtorrent
|
|||
void operator=(integer_type const&);
|
||||
|
||||
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
||||
// are accessors that return the respective type. If the ``entry`` object isn't of the
|
||||
// type you request, the accessor will throw libtorrent_exception (which derives from
|
||||
// ``std::runtime_error``). You can ask an ``entry`` for its type through the
|
||||
// ``type()`` function.
|
||||
// are accessors that return the respective type. If the ``entry`` object
|
||||
// isn't of the type you request, the accessor will throw
|
||||
// libtorrent_exception (which derives from ``std::runtime_error``). You
|
||||
// can ask an ``entry`` for its type through the ``type()`` function.
|
||||
//
|
||||
// If you want to create an ``entry`` you give it the type you want it to have in its
|
||||
// constructor, and then use one of the non-const accessors to get a reference which you then
|
||||
// can assign the value you want it to have.
|
||||
// If you want to create an ``entry`` you give it the type you want it to
|
||||
// have in its constructor, and then use one of the non-const accessors
|
||||
// to get a reference which you then can assign the value you want it to
|
||||
// have.
|
||||
//
|
||||
// The typical code to get info from a torrent file will then look like this::
|
||||
// The typical code to get info from a torrent file will then look like
|
||||
// this::
|
||||
//
|
||||
// entry torrent_file;
|
||||
// // ...
|
||||
|
@ -187,8 +189,8 @@ namespace libtorrent
|
|||
// }
|
||||
//
|
||||
//
|
||||
// To make it easier to extract information from a torrent file, the class torrent_info
|
||||
// exists.
|
||||
// To make it easier to extract information from a torrent file, the
|
||||
// class torrent_info exists.
|
||||
integer_type& integer();
|
||||
const integer_type& integer() const;
|
||||
string_type& string();
|
||||
|
@ -201,16 +203,17 @@ namespace libtorrent
|
|||
// swaps the content of *this* with ``e``.
|
||||
void swap(entry& e);
|
||||
|
||||
// All of these functions requires the entry to be a dictionary, if it isn't they
|
||||
// will throw ``libtorrent::type_error``.
|
||||
// All of these functions requires the entry to be a dictionary, if it
|
||||
// isn't they will throw ``libtorrent::type_error``.
|
||||
//
|
||||
// The non-const versions of the ``operator[]`` will return a reference to either
|
||||
// the existing element at the given key or, if there is no element with the
|
||||
// given key, a reference to a newly inserted element at that key.
|
||||
// The non-const versions of the ``operator[]`` will return a reference
|
||||
// to either the existing element at the given key or, if there is no
|
||||
// element with the given key, a reference to a newly inserted element at
|
||||
// that key.
|
||||
//
|
||||
// The const version of ``operator[]`` will only return a reference to an
|
||||
// existing element at the given key. If the key is not found, it will throw
|
||||
// ``libtorrent::type_error``.
|
||||
// existing element at the given key. If the key is not found, it will
|
||||
// throw ``libtorrent::type_error``.
|
||||
entry& operator[](char const* key);
|
||||
entry& operator[](std::string const& key);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
@ -218,12 +221,12 @@ namespace libtorrent
|
|||
const entry& operator[](std::string const& key) const;
|
||||
#endif
|
||||
|
||||
// These functions requires the entry to be a dictionary, if it isn't they
|
||||
// will throw ``libtorrent::type_error``.
|
||||
// These functions requires the entry to be a dictionary, if it isn't
|
||||
// they will throw ``libtorrent::type_error``.
|
||||
//
|
||||
// They will look for an element at the given key in the dictionary, if the
|
||||
// element cannot be found, they will return 0. If an element with the given
|
||||
// key is found, the return a pointer to it.
|
||||
// They will look for an element at the given key in the dictionary, if
|
||||
// the element cannot be found, they will return 0. If an element with
|
||||
// the given key is found, the return a pointer to it.
|
||||
entry* find_key(char const* key);
|
||||
entry const* find_key(char const* key) const;
|
||||
entry* find_key(std::string const& key);
|
||||
|
@ -264,20 +267,17 @@ namespace libtorrent
|
|||
integer_type data[(union_size + sizeof(integer_type) - 1)
|
||||
/ sizeof(integer_type)];
|
||||
|
||||
// the bitfield is used so that the m_type_queried
|
||||
// field still fits, so that the ABI is the same for
|
||||
// debug builds and release builds. It appears to be
|
||||
// very hard to match debug builds with debug versions
|
||||
// of libtorrent
|
||||
// the bitfield is used so that the m_type_queried field still fits, so
|
||||
// that the ABI is the same for debug builds and release builds. It
|
||||
// appears to be very hard to match debug builds with debug versions of
|
||||
// libtorrent
|
||||
boost::uint8_t m_type:7;
|
||||
|
||||
public:
|
||||
// in debug mode this is set to false by bdecode
|
||||
// to indicate that the program has not yet queried
|
||||
// the type of this entry, and sould not assume
|
||||
// that it has a certain type. This is asserted in
|
||||
// the accessor functions. This does not apply if
|
||||
// exceptions are used.
|
||||
// in debug mode this is set to false by bdecode to indicate that the
|
||||
// program has not yet queried the type of this entry, and sould not
|
||||
// assume that it has a certain type. This is asserted in the accessor
|
||||
// functions. This does not apply if exceptions are used.
|
||||
mutable boost::uint8_t m_type_queried:1;
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,8 @@ namespace libtorrent { namespace dht
|
|||
, dht_settings const& settings, entry const* state = 0);
|
||||
virtual ~dht_tracker();
|
||||
|
||||
void start(entry const& bootstrap);
|
||||
void start(entry const& bootstrap
|
||||
, find_data::nodes_callback const& f);
|
||||
void stop();
|
||||
|
||||
void add_node(udp::endpoint node);
|
||||
|
|
|
@ -61,12 +61,11 @@ struct find_data : traversal_algorithm
|
|||
{
|
||||
typedef boost::function<void(std::vector<std::pair<node_entry, std::string> > const&)> nodes_callback;
|
||||
|
||||
void got_write_token(node_id const& n, std::string const& write_token)
|
||||
{ m_write_tokens[n] = write_token; }
|
||||
|
||||
find_data(node_impl& node, node_id target
|
||||
, nodes_callback const& ncallback);
|
||||
|
||||
void got_write_token(node_id const& n, std::string const& write_token);
|
||||
|
||||
virtual void start();
|
||||
|
||||
virtual char const* name() const;
|
||||
|
|
|
@ -599,6 +599,17 @@ namespace libtorrent {
|
|||
return msg;
|
||||
}
|
||||
|
||||
std::string dht_put_alert::message() const
|
||||
{
|
||||
char msg[1050];
|
||||
snprintf(msg, sizeof(msg), "DHT put complete (key=%s sig=%s salt=%s seq=%" PRId64 ")"
|
||||
, to_hex(std::string(&public_key[0], 32)).c_str()
|
||||
, to_hex(std::string(&signature[0], 64)).c_str()
|
||||
, salt.c_str()
|
||||
, seq);
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
} // namespace libtorrent
|
||||
|
||||
|
|
|
@ -491,8 +491,60 @@ namespace libtorrent
|
|||
|
||||
void entry::swap(entry& e)
|
||||
{
|
||||
// not implemented
|
||||
TORRENT_ASSERT(false);
|
||||
bool clear_this = false;
|
||||
bool clear_that = false;
|
||||
|
||||
if (m_type == undefined_t && e.m_type == undefined_t)
|
||||
return;
|
||||
|
||||
if (m_type == undefined_t)
|
||||
{
|
||||
construct((data_type)e.m_type);
|
||||
clear_that = true;
|
||||
}
|
||||
|
||||
if (e.m_type == undefined_t)
|
||||
{
|
||||
e.construct((data_type)m_type);
|
||||
clear_this = true;
|
||||
}
|
||||
|
||||
if (m_type == e.m_type)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case int_t:
|
||||
std::swap(*reinterpret_cast<integer_type*>(data)
|
||||
, *reinterpret_cast<integer_type*>(e.data));
|
||||
break;
|
||||
case string_t:
|
||||
std::swap(*reinterpret_cast<string_type*>(data)
|
||||
, *reinterpret_cast<string_type*>(e.data));
|
||||
break;
|
||||
case list_t:
|
||||
std::swap(*reinterpret_cast<list_type*>(data)
|
||||
, *reinterpret_cast<list_type*>(e.data));
|
||||
break;
|
||||
case dictionary_t:
|
||||
std::swap(*reinterpret_cast<dictionary_type*>(data)
|
||||
, *reinterpret_cast<dictionary_type*>(e.data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (clear_this)
|
||||
destruct();
|
||||
|
||||
if (clear_that)
|
||||
e.destruct();
|
||||
}
|
||||
else
|
||||
{
|
||||
// currently, only swapping entries of the same type or where one
|
||||
// of the entries is uninitialized is supported.
|
||||
TORRENT_ASSERT(false && "not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
std::string entry::to_string() const
|
||||
|
|
|
@ -246,7 +246,8 @@ namespace libtorrent { namespace dht
|
|||
// defined in node.cpp
|
||||
extern void nop();
|
||||
|
||||
void dht_tracker::start(entry const& bootstrap)
|
||||
void dht_tracker::start(entry const& bootstrap
|
||||
, find_data::nodes_callback const& f)
|
||||
{
|
||||
std::vector<udp::endpoint> initial_nodes;
|
||||
|
||||
|
@ -268,7 +269,7 @@ namespace libtorrent { namespace dht
|
|||
|
||||
m_refresh_timer.expires_from_now(seconds(5), ec);
|
||||
m_refresh_timer.async_wait(boost::bind(&dht_tracker::refresh_timeout, self(), _1));
|
||||
m_dht.bootstrap(initial_nodes, boost::bind(&libtorrent::dht::nop));
|
||||
m_dht.bootstrap(initial_nodes, f);
|
||||
}
|
||||
|
||||
void dht_tracker::stop()
|
||||
|
|
|
@ -80,6 +80,10 @@ void find_data_observer::reply(msg const& m)
|
|||
node_id(id->string_ptr()), token->string_value());
|
||||
}
|
||||
|
||||
// in case we didn't know the id of this peer when we sent the message to
|
||||
// it. For instance if it's a bootstrap node.
|
||||
set_id(node_id(id->string_ptr()));
|
||||
|
||||
traversal_observer::reply(m);
|
||||
done();
|
||||
}
|
||||
|
@ -110,6 +114,15 @@ void find_data::start()
|
|||
traversal_algorithm::start();
|
||||
}
|
||||
|
||||
void find_data::got_write_token(node_id const& n, std::string const& write_token)
|
||||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] adding write "
|
||||
"token '" << to_hex(write_token) << "' under id '" << to_hex(n.to_string()) << "'";
|
||||
#endif
|
||||
m_write_tokens[n] = write_token;
|
||||
}
|
||||
|
||||
observer_ptr find_data::new_observer(void* ptr
|
||||
, udp::endpoint const& ep, node_id const& id)
|
||||
{
|
||||
|
@ -129,7 +142,7 @@ void find_data::done()
|
|||
m_done = true;
|
||||
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] find_data DONE";
|
||||
TORRENT_LOG(traversal) << "[" << this << "] " << name() << " DONE";
|
||||
#endif
|
||||
|
||||
std::vector<std::pair<node_entry, std::string> > results;
|
||||
|
@ -138,13 +151,31 @@ void find_data::done()
|
|||
, 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;
|
||||
if ((o->flags & observer::flag_alive) == 0)
|
||||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] not alive: "
|
||||
<< o->target_ep();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
std::map<node_id, std::string>::iterator j = m_write_tokens.find(o->id());
|
||||
if (j == m_write_tokens.end()) continue;
|
||||
if (j == m_write_tokens.end())
|
||||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] no write token: "
|
||||
<< o->target_ep();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
results.push_back(std::make_pair(node_entry(o->id(), o->target_ep()), j->second));
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] "
|
||||
<< o->target_ep();
|
||||
#endif
|
||||
--num_results;
|
||||
}
|
||||
|
||||
if (m_nodes_callback) m_nodes_callback(results);
|
||||
|
||||
traversal_algorithm::done();
|
||||
|
|
|
@ -177,8 +177,8 @@ void get_item::done()
|
|||
void get_item::put(std::vector<std::pair<node_entry, std::string> > const& v)
|
||||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(node) << "sending put [ v: " << m_data.value()
|
||||
<< " seq: " << (m_data.is_mutable() ? m_data.seq() : -1)
|
||||
TORRENT_LOG(node) << "sending put [ v: \"" << m_data.value()
|
||||
<< "\" seq: " << (m_data.is_mutable() ? m_data.seq() : -1)
|
||||
<< " nodes: " << v.size() << " ]" ;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ char const* bootstrap::name() const { return "bootstrap"; }
|
|||
void bootstrap::done()
|
||||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << " [" << this << "]"
|
||||
TORRENT_LOG(traversal) << "[" << this << "]"
|
||||
<< " bootstrap done, pinging remaining nodes";
|
||||
#endif
|
||||
|
||||
|
|
|
@ -79,7 +79,9 @@ traversal_algorithm::traversal_algorithm(
|
|||
{
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(traversal) << "[" << this << "] NEW"
|
||||
" target: " << target << " k: " << m_node.m_table.bucket_size();
|
||||
" target: " << target
|
||||
<< " k: " << m_node.m_table.bucket_size()
|
||||
;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -151,7 +153,9 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig
|
|||
<< " address: " << o->target_addr()
|
||||
<< " existing node: "
|
||||
<< (*j)->id() << " " << (*j)->target_addr()
|
||||
<< " distance: " << distance_exp(m_target, o->id());
|
||||
<< " distance: " << distance_exp(m_target, o->id())
|
||||
<< " type: " << name()
|
||||
;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
@ -163,7 +167,9 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig
|
|||
TORRENT_LOG(traversal) << "[" << this << "] ADD id: " << id
|
||||
<< " address: " << addr
|
||||
<< " distance: " << distance_exp(m_target, id)
|
||||
<< " invoke-count: " << m_invoke_count;
|
||||
<< " invoke-count: " << m_invoke_count
|
||||
<< " type: " << name()
|
||||
;
|
||||
#endif
|
||||
i = m_results.insert(i, o);
|
||||
}
|
||||
|
@ -268,7 +274,9 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
|||
<< " distance: " << distance_exp(m_target, o->id())
|
||||
<< " addr: " << o->target_ep()
|
||||
<< " branch-factor: " << m_branch_factor
|
||||
<< " invoke-count: " << m_invoke_count;
|
||||
<< " invoke-count: " << m_invoke_count
|
||||
<< " type: " << name()
|
||||
;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
|
@ -285,7 +293,9 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
|||
<< " distance: " << distance_exp(m_target, o->id())
|
||||
<< " addr: " << o->target_ep()
|
||||
<< " branch-factor: " << m_branch_factor
|
||||
<< " invoke-count: " << m_invoke_count;
|
||||
<< " invoke-count: " << m_invoke_count
|
||||
<< " type: " << name()
|
||||
;
|
||||
#endif
|
||||
// don't tell the routing table about
|
||||
// node ids that we just generated ourself
|
||||
|
@ -322,7 +332,8 @@ void traversal_algorithm::done()
|
|||
<< results_target
|
||||
<< " id: " << o->id()
|
||||
<< " distance: " << distance_exp(m_target, o->id())
|
||||
<< " address: " << o->target_ep();
|
||||
<< " address: " << o->target_ep()
|
||||
;
|
||||
--results_target;
|
||||
int dist = distance_exp(m_target, o->id());
|
||||
if (dist < closest_target) closest_target = dist;
|
||||
|
@ -330,7 +341,9 @@ void traversal_algorithm::done()
|
|||
}
|
||||
|
||||
TORRENT_LOG(traversal) << "[" << this << "] COMPLETED "
|
||||
<< "distance: " << closest_target;
|
||||
<< "distance: " << closest_target
|
||||
<< " type: " << name()
|
||||
;
|
||||
|
||||
#endif
|
||||
// delete all our references to the observer objects so
|
||||
|
@ -393,6 +406,7 @@ bool traversal_algorithm::add_requests()
|
|||
<< " invoke-count: " << m_invoke_count
|
||||
<< " branch-factor: " << m_branch_factor
|
||||
<< " distance: " << distance_exp(m_target, (*i)->id())
|
||||
<< " type: " << name()
|
||||
;
|
||||
#endif
|
||||
|
||||
|
|
|
@ -902,7 +902,7 @@ namespace libtorrent
|
|||
sha1_hash ret = hasher(&buf[0], buf.size()).final();
|
||||
|
||||
#ifndef TORRENT_DISABLE_DHT
|
||||
TORRENT_ASYNC_CALL1(dht_put_item, data);
|
||||
TORRENT_ASYNC_CALL2(dht_put_item, data, ret);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -5693,6 +5693,12 @@ retry:
|
|||
void session_impl::start_dht()
|
||||
{ start_dht(m_dht_state); }
|
||||
|
||||
void on_bootstrap(alert_manager& alerts)
|
||||
{
|
||||
if (alerts.should_post<dht_bootstrap_alert>())
|
||||
alerts.post_alert(dht_bootstrap_alert());
|
||||
}
|
||||
|
||||
void session_impl::start_dht(entry const& startup_state)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
@ -5706,7 +5712,7 @@ retry:
|
|||
m_dht->add_router_node(*i);
|
||||
}
|
||||
|
||||
m_dht->start(startup_state);
|
||||
m_dht->start(startup_state, boost::bind(&on_bootstrap, boost::ref(m_alerts)));
|
||||
|
||||
m_udp_socket.subscribe(m_dht.get());
|
||||
}
|
||||
|
@ -5806,15 +5812,20 @@ retry:
|
|||
, this, _1), salt);
|
||||
}
|
||||
|
||||
void nop() {}
|
||||
|
||||
void session_impl::dht_put_item(entry data)
|
||||
void on_dht_put(alert_manager& alerts, sha1_hash target)
|
||||
{
|
||||
if (!m_dht) return;
|
||||
m_dht->put_item(data, boost::bind(&nop));
|
||||
if (alerts.should_post<dht_put_alert>())
|
||||
alerts.post_alert(dht_put_alert(target));
|
||||
}
|
||||
|
||||
void put_mutable_callback(dht::item& i
|
||||
void session_impl::dht_put_item(entry data, sha1_hash target)
|
||||
{
|
||||
if (!m_dht) return;
|
||||
m_dht->put_item(data, boost::bind(&on_dht_put, boost::ref(m_alerts)
|
||||
, target));
|
||||
}
|
||||
|
||||
void put_mutable_callback(alert_manager& alerts, dht::item& i
|
||||
, boost::function<void(entry&, boost::array<char,64>&
|
||||
, boost::uint64_t&, std::string const&)> cb)
|
||||
{
|
||||
|
@ -5825,6 +5836,9 @@ retry:
|
|||
std::string salt = i.salt();
|
||||
cb(value, sig, seq, salt);
|
||||
i.assign(value, salt, seq, pk.data(), sig.data());
|
||||
|
||||
if (alerts.should_post<dht_put_alert>())
|
||||
alerts.post_alert(dht_put_alert(pk, sig, salt, seq));
|
||||
}
|
||||
|
||||
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
||||
|
@ -5833,7 +5847,8 @@ retry:
|
|||
, std::string salt)
|
||||
{
|
||||
if (!m_dht) return;
|
||||
m_dht->put_item(key.data(), boost::bind(&put_mutable_callback, _1, cb), salt);
|
||||
m_dht->put_item(key.data(), boost::bind(&put_mutable_callback
|
||||
, boost::ref(m_alerts), _1, cb), salt);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,4 +18,5 @@ project tools
|
|||
|
||||
exe parse_hash_fails : parse_hash_fails.cpp ;
|
||||
exe parse_request_log : parse_request_log.cpp ;
|
||||
exe dht : dht_put.cpp ;
|
||||
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2014, Arvid Norberg
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/escape_string.hpp" // for from_hex
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/bencode.hpp" // for bencode()
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace libtorrent;
|
||||
|
||||
void usage()
|
||||
{
|
||||
fprintf(stderr,
|
||||
"USAGE:\ndht <command> <arg>\n\nCOMMANDS:\n"
|
||||
"get <hash> - retrieves and prints out the immutable\n"
|
||||
" item stored under hash.\n"
|
||||
"put <string> - puts the specified string as an immutable\n"
|
||||
" item onto the DHT. The resulting target hash\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
std::auto_ptr<alert> wait_for_alert(session& s, int alert_type)
|
||||
{
|
||||
std::auto_ptr<alert> ret;
|
||||
bool found = false;
|
||||
while (!found)
|
||||
{
|
||||
s.wait_for_alert(seconds(5));
|
||||
|
||||
std::deque<alert*> alerts;
|
||||
s.pop_alerts(&alerts);
|
||||
for (std::deque<alert*>::iterator i = alerts.begin()
|
||||
, end(alerts.end()); i != end; ++i)
|
||||
{
|
||||
if ((*i)->type() != alert_type)
|
||||
{
|
||||
static int spinner = 0;
|
||||
static const char anim[] = {'-', '\\', '|', '/'};
|
||||
printf("\r%c", anim[spinner]);
|
||||
fflush(stdout);
|
||||
spinner = (spinner + 1) & 3;
|
||||
//print some alerts?
|
||||
delete *i;
|
||||
continue;
|
||||
}
|
||||
ret = std::auto_ptr<alert>(*i);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
session s;
|
||||
s.set_alert_mask(0xffffffff);
|
||||
|
||||
s.add_dht_router(std::pair<std::string, int>("router.utorrent.com", 6881));
|
||||
|
||||
FILE* f = fopen(".dht", "rb");
|
||||
if (f != NULL)
|
||||
{
|
||||
fseek(f, 0, SEEK_END);
|
||||
int size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
if (size > 0)
|
||||
{
|
||||
std::vector<char> state;
|
||||
state.resize(size);
|
||||
fread(&state[0], 1, state.size(), f);
|
||||
|
||||
lazy_entry e;
|
||||
error_code ec;
|
||||
lazy_bdecode(&state[0], &state[0] + state.size(), e, ec);
|
||||
if (ec)
|
||||
fprintf(stderr, "failed to parse .dht file: (%d) %s\n"
|
||||
, ec.value(), ec.message().c_str());
|
||||
else
|
||||
s.load_state(e);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
printf("bootstrapping\n");
|
||||
wait_for_alert(s, dht_bootstrap_alert::alert_type);
|
||||
|
||||
// skip pointer to self
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argc < 1) usage();
|
||||
|
||||
if (strcmp(argv[0], "get") == 0)
|
||||
{
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argc < 1) usage();
|
||||
|
||||
if (strlen(argv[0]) != 40)
|
||||
{
|
||||
fprintf(stderr, "the hash is expected to be 40 hex characters\n");
|
||||
usage();
|
||||
}
|
||||
sha1_hash target;
|
||||
from_hex(argv[0], 40, (char*)&target[0]);
|
||||
|
||||
s.dht_get_item(target);
|
||||
|
||||
printf("GET %s\n", to_hex(target.to_string()).c_str());
|
||||
|
||||
std::auto_ptr<alert> a = wait_for_alert(s, dht_immutable_item_alert::alert_type);
|
||||
|
||||
dht_immutable_item_alert* item = alert_cast<dht_immutable_item_alert>(a.get());
|
||||
entry data;
|
||||
if (item)
|
||||
data.swap(item->item);
|
||||
|
||||
printf("%s", data.to_string().c_str());
|
||||
}
|
||||
else if (strcmp(argv[0], "put") == 0)
|
||||
{
|
||||
++argv;
|
||||
--argc;
|
||||
|
||||
if (argc < 1) usage();
|
||||
|
||||
entry data;
|
||||
data = std::string(argv[0]);
|
||||
|
||||
sha1_hash target = s.dht_put_item(data);
|
||||
|
||||
printf("PUT %s\n", to_hex(target.to_string()).c_str());
|
||||
|
||||
wait_for_alert(s, dht_put_alert::alert_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
usage();
|
||||
}
|
||||
|
||||
entry e;
|
||||
s.save_state(e, session::save_dht_state);
|
||||
std::vector<char> state;
|
||||
bencode(std::back_inserter(state), e);
|
||||
f = fopen(".dht", "wb+");
|
||||
if (f == NULL)
|
||||
{
|
||||
fprintf(stderr, "failed to open file .dht for writing");
|
||||
return 1;
|
||||
}
|
||||
fwrite(&state[0], 1, state.size(), f);
|
||||
fclose(f);
|
||||
}
|
||||
|
Loading…
Reference in New Issue