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
|
* allow force_announce to only affect a single tracker
|
||||||
* add moving_storage field to torrent_status
|
* add moving_storage field to torrent_status
|
||||||
* expose UPnP and NAT-PMP mapping in session object
|
* 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
|
* support building on android
|
||||||
* improved support for web seeds that don't support keep-alive
|
* improved support for web seeds that don't support keep-alive
|
||||||
* improve DHT routing table to return better nodes (lower RTT and closer
|
* 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 uTP edge case where udp socket buffer fills up
|
||||||
* fix nagle implementation in uTP
|
* fix nagle implementation in uTP
|
||||||
|
|
||||||
|
* fix dht_bootstrap_alert being posted
|
||||||
* SetFileValidData fix on windows (prevents zero-fill)
|
* SetFileValidData fix on windows (prevents zero-fill)
|
||||||
* fix minor lock_files issue on unix
|
* fix minor lock_files issue on unix
|
||||||
|
|
||||||
|
|
|
@ -1520,8 +1520,8 @@ namespace libtorrent
|
||||||
int reason;
|
int reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is generated when a DHT node announces to an info-hash on our DHT node. It belongs
|
// This alert is generated when a DHT node announces to an info-hash on our
|
||||||
// to the ``dht_notification`` category.
|
// DHT node. It belongs to the ``dht_notification`` category.
|
||||||
struct TORRENT_EXPORT dht_announce_alert: alert
|
struct TORRENT_EXPORT dht_announce_alert: alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
|
@ -1542,8 +1542,8 @@ namespace libtorrent
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is generated when a DHT node sends a ``get_peers`` message to our DHT node.
|
// This alert is generated when a DHT node sends a ``get_peers`` message to
|
||||||
// It belongs to the ``dht_notification`` category.
|
// our DHT node. It belongs to the ``dht_notification`` category.
|
||||||
struct TORRENT_EXPORT dht_get_peers_alert: alert
|
struct TORRENT_EXPORT dht_get_peers_alert: alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
|
@ -1590,21 +1590,22 @@ namespace libtorrent
|
||||||
num_channels
|
num_channels
|
||||||
};
|
};
|
||||||
|
|
||||||
// an array of samples. The enum describes what each
|
// an array of samples. The enum describes what each sample is a
|
||||||
// sample is a measurement of. All of these are raw, and not smoothing is performed.
|
// measurement of. All of these are raw, and not smoothing is performed.
|
||||||
int transferred[num_channels];
|
int transferred[num_channels];
|
||||||
|
|
||||||
// the number of milliseconds during which these stats
|
// the number of milliseconds during which these stats were collected.
|
||||||
// were collected. This is typically just above 1000, but if CPU is
|
// This is typically just above 1000, but if CPU is limited, it may be
|
||||||
// limited, it may be higher than that.
|
// higher than that.
|
||||||
int interval;
|
int interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is posted when the disk cache has been flushed for a specific torrent
|
// This alert is posted when the disk cache has been flushed for a specific
|
||||||
// as a result of a call to torrent_handle::flush_cache(). This alert belongs to the
|
// torrent as a result of a call to torrent_handle::flush_cache(). This
|
||||||
// ``storage_notification`` category, which must be enabled to let this alert through.
|
// alert belongs to the ``storage_notification`` category, which must be
|
||||||
// The alert is also posted when removing a torrent from the session, once the outstanding
|
// enabled to let this alert through. The alert is also posted when removing
|
||||||
// cache flush is complete and the torrent does no longer have any files open.
|
// 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
|
struct TORRENT_EXPORT cache_flushed_alert: torrent_alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
|
@ -1647,8 +1648,8 @@ namespace libtorrent
|
||||||
std::string str;
|
std::string str;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is generated when we receive a local service discovery message from a peer
|
// This alert is generated when we receive a local service discovery message
|
||||||
// for a torrent we're currently participating in.
|
// from a peer for a torrent we're currently participating in.
|
||||||
struct TORRENT_EXPORT lsd_peer_alert: peer_alert
|
struct TORRENT_EXPORT lsd_peer_alert: peer_alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
|
@ -1663,9 +1664,9 @@ namespace libtorrent
|
||||||
virtual std::string message() const;
|
virtual std::string message() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This alert is posted whenever a tracker responds with a ``trackerid``. The tracker ID
|
// This alert is posted whenever a tracker responds with a ``trackerid``.
|
||||||
// is like a cookie. The libtorrent will store the tracker ID for this tracker and
|
// The tracker ID is like a cookie. The libtorrent will store the tracker ID
|
||||||
// repeat it in subsequent announces.
|
// for this tracker and repeat it in subsequent announces.
|
||||||
struct TORRENT_EXPORT trackerid_alert: tracker_alert
|
struct TORRENT_EXPORT trackerid_alert: tracker_alert
|
||||||
{
|
{
|
||||||
// internal
|
// internal
|
||||||
|
@ -2003,6 +2004,43 @@ namespace libtorrent
|
||||||
// the data for this item
|
// the data for this item
|
||||||
entry 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
|
#undef TORRENT_DEFINE_ALERT
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,7 +323,7 @@ namespace libtorrent
|
||||||
void dht_get_mutable_item(boost::array<char, 32> key
|
void dht_get_mutable_item(boost::array<char, 32> key
|
||||||
, std::string salt = std::string());
|
, 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
|
void dht_put_mutable_item(boost::array<char, 32> key
|
||||||
, boost::function<void(entry&, boost::array<char,64>&
|
, boost::function<void(entry&, boost::array<char,64>&
|
||||||
|
|
|
@ -149,16 +149,18 @@ namespace libtorrent
|
||||||
void operator=(integer_type const&);
|
void operator=(integer_type const&);
|
||||||
|
|
||||||
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
||||||
// are accessors that return the respective type. If the ``entry`` object isn't of the
|
// are accessors that return the respective type. If the ``entry`` object
|
||||||
// type you request, the accessor will throw libtorrent_exception (which derives from
|
// isn't of the type you request, the accessor will throw
|
||||||
// ``std::runtime_error``). You can ask an ``entry`` for its type through the
|
// libtorrent_exception (which derives from ``std::runtime_error``). You
|
||||||
// ``type()`` function.
|
// 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
|
// If you want to create an ``entry`` you give it the type you want it to
|
||||||
// constructor, and then use one of the non-const accessors to get a reference which you then
|
// have in its constructor, and then use one of the non-const accessors
|
||||||
// can assign the value you want it to have.
|
// 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;
|
// entry torrent_file;
|
||||||
// // ...
|
// // ...
|
||||||
|
@ -187,8 +189,8 @@ namespace libtorrent
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
// To make it easier to extract information from a torrent file, the class torrent_info
|
// To make it easier to extract information from a torrent file, the
|
||||||
// exists.
|
// class torrent_info exists.
|
||||||
integer_type& integer();
|
integer_type& integer();
|
||||||
const integer_type& integer() const;
|
const integer_type& integer() const;
|
||||||
string_type& string();
|
string_type& string();
|
||||||
|
@ -201,16 +203,17 @@ namespace libtorrent
|
||||||
// swaps the content of *this* with ``e``.
|
// swaps the content of *this* with ``e``.
|
||||||
void swap(entry& e);
|
void swap(entry& e);
|
||||||
|
|
||||||
// All of these functions requires the entry to be a dictionary, if it isn't they
|
// All of these functions requires the entry to be a dictionary, if it
|
||||||
// will throw ``libtorrent::type_error``.
|
// isn't they will throw ``libtorrent::type_error``.
|
||||||
//
|
//
|
||||||
// The non-const versions of the ``operator[]`` will return a reference to either
|
// The non-const versions of the ``operator[]`` will return a reference
|
||||||
// the existing element at the given key or, if there is no element with the
|
// to either the existing element at the given key or, if there is no
|
||||||
// given key, a reference to a newly inserted element at that key.
|
// 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
|
// 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
|
// existing element at the given key. If the key is not found, it will
|
||||||
// ``libtorrent::type_error``.
|
// throw ``libtorrent::type_error``.
|
||||||
entry& operator[](char const* key);
|
entry& operator[](char const* key);
|
||||||
entry& operator[](std::string const& key);
|
entry& operator[](std::string const& key);
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
@ -218,12 +221,12 @@ namespace libtorrent
|
||||||
const entry& operator[](std::string const& key) const;
|
const entry& operator[](std::string const& key) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// These functions requires the entry to be a dictionary, if it isn't they
|
// These functions requires the entry to be a dictionary, if it isn't
|
||||||
// will throw ``libtorrent::type_error``.
|
// they will throw ``libtorrent::type_error``.
|
||||||
//
|
//
|
||||||
// They will look for an element at the given key in the dictionary, if the
|
// They will look for an element at the given key in the dictionary, if
|
||||||
// element cannot be found, they will return 0. If an element with the given
|
// the element cannot be found, they will return 0. If an element with
|
||||||
// key is found, the return a pointer to it.
|
// the given key is found, the return a pointer to it.
|
||||||
entry* find_key(char const* key);
|
entry* find_key(char const* key);
|
||||||
entry const* find_key(char const* key) const;
|
entry const* find_key(char const* key) const;
|
||||||
entry* find_key(std::string const& key);
|
entry* find_key(std::string const& key);
|
||||||
|
@ -264,20 +267,17 @@ namespace libtorrent
|
||||||
integer_type data[(union_size + sizeof(integer_type) - 1)
|
integer_type data[(union_size + sizeof(integer_type) - 1)
|
||||||
/ sizeof(integer_type)];
|
/ sizeof(integer_type)];
|
||||||
|
|
||||||
// the bitfield is used so that the m_type_queried
|
// the bitfield is used so that the m_type_queried field still fits, so
|
||||||
// field still fits, so that the ABI is the same for
|
// that the ABI is the same for debug builds and release builds. It
|
||||||
// debug builds and release builds. It appears to be
|
// appears to be very hard to match debug builds with debug versions of
|
||||||
// very hard to match debug builds with debug versions
|
// libtorrent
|
||||||
// of libtorrent
|
|
||||||
boost::uint8_t m_type:7;
|
boost::uint8_t m_type:7;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// in debug mode this is set to false by bdecode
|
// in debug mode this is set to false by bdecode to indicate that the
|
||||||
// to indicate that the program has not yet queried
|
// program has not yet queried the type of this entry, and sould not
|
||||||
// the type of this entry, and sould not assume
|
// assume that it has a certain type. This is asserted in the accessor
|
||||||
// that it has a certain type. This is asserted in
|
// functions. This does not apply if exceptions are used.
|
||||||
// the accessor functions. This does not apply if
|
|
||||||
// exceptions are used.
|
|
||||||
mutable boost::uint8_t m_type_queried:1;
|
mutable boost::uint8_t m_type_queried:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,8 @@ namespace libtorrent { namespace dht
|
||||||
, dht_settings const& settings, entry const* state = 0);
|
, dht_settings const& settings, entry const* state = 0);
|
||||||
virtual ~dht_tracker();
|
virtual ~dht_tracker();
|
||||||
|
|
||||||
void start(entry const& bootstrap);
|
void start(entry const& bootstrap
|
||||||
|
, find_data::nodes_callback const& f);
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void add_node(udp::endpoint node);
|
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;
|
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
|
find_data(node_impl& node, node_id target
|
||||||
, nodes_callback const& ncallback);
|
, nodes_callback const& ncallback);
|
||||||
|
|
||||||
|
void got_write_token(node_id const& n, std::string const& write_token);
|
||||||
|
|
||||||
virtual void start();
|
virtual void start();
|
||||||
|
|
||||||
virtual char const* name() const;
|
virtual char const* name() const;
|
||||||
|
|
|
@ -599,6 +599,17 @@ namespace libtorrent {
|
||||||
return msg;
|
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
|
} // namespace libtorrent
|
||||||
|
|
||||||
|
|
|
@ -491,8 +491,60 @@ namespace libtorrent
|
||||||
|
|
||||||
void entry::swap(entry& e)
|
void entry::swap(entry& e)
|
||||||
{
|
{
|
||||||
// not implemented
|
bool clear_this = false;
|
||||||
TORRENT_ASSERT(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
|
std::string entry::to_string() const
|
||||||
|
|
|
@ -246,7 +246,8 @@ namespace libtorrent { namespace dht
|
||||||
// defined in node.cpp
|
// defined in node.cpp
|
||||||
extern void nop();
|
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;
|
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.expires_from_now(seconds(5), ec);
|
||||||
m_refresh_timer.async_wait(boost::bind(&dht_tracker::refresh_timeout, self(), _1));
|
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()
|
void dht_tracker::stop()
|
||||||
|
|
|
@ -80,6 +80,10 @@ void find_data_observer::reply(msg const& m)
|
||||||
node_id(id->string_ptr()), token->string_value());
|
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);
|
traversal_observer::reply(m);
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
@ -110,6 +114,15 @@ void find_data::start()
|
||||||
traversal_algorithm::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
|
observer_ptr find_data::new_observer(void* ptr
|
||||||
, udp::endpoint const& ep, node_id const& id)
|
, udp::endpoint const& ep, node_id const& id)
|
||||||
{
|
{
|
||||||
|
@ -129,7 +142,7 @@ void find_data::done()
|
||||||
m_done = true;
|
m_done = true;
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << "[" << this << "] find_data DONE";
|
TORRENT_LOG(traversal) << "[" << this << "] " << name() << " DONE";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::pair<node_entry, std::string> > results;
|
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)
|
, end(m_results.end()); i != end && num_results > 0; ++i)
|
||||||
{
|
{
|
||||||
observer_ptr const& o = *i;
|
observer_ptr const& o = *i;
|
||||||
if (o->flags & observer::flag_no_id) continue;
|
if ((o->flags & observer::flag_alive) == 0)
|
||||||
if ((o->flags & observer::flag_queried) == 0) continue;
|
{
|
||||||
|
#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());
|
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));
|
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;
|
--num_results;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_nodes_callback) m_nodes_callback(results);
|
if (m_nodes_callback) m_nodes_callback(results);
|
||||||
|
|
||||||
traversal_algorithm::done();
|
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)
|
void get_item::put(std::vector<std::pair<node_entry, std::string> > const& v)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(node) << "sending put [ v: " << m_data.value()
|
TORRENT_LOG(node) << "sending put [ v: \"" << m_data.value()
|
||||||
<< " seq: " << (m_data.is_mutable() ? m_data.seq() : -1)
|
<< "\" seq: " << (m_data.is_mutable() ? m_data.seq() : -1)
|
||||||
<< " nodes: " << v.size() << " ]" ;
|
<< " nodes: " << v.size() << " ]" ;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ char const* bootstrap::name() const { return "bootstrap"; }
|
||||||
void bootstrap::done()
|
void bootstrap::done()
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " [" << this << "]"
|
TORRENT_LOG(traversal) << "[" << this << "]"
|
||||||
<< " bootstrap done, pinging remaining nodes";
|
<< " bootstrap done, pinging remaining nodes";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,9 @@ traversal_algorithm::traversal_algorithm(
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << "[" << this << "] NEW"
|
TORRENT_LOG(traversal) << "[" << this << "] NEW"
|
||||||
" target: " << target << " k: " << m_node.m_table.bucket_size();
|
" target: " << target
|
||||||
|
<< " k: " << m_node.m_table.bucket_size()
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +153,9 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig
|
||||||
<< " address: " << o->target_addr()
|
<< " address: " << o->target_addr()
|
||||||
<< " existing node: "
|
<< " existing node: "
|
||||||
<< (*j)->id() << " " << (*j)->target_addr()
|
<< (*j)->id() << " " << (*j)->target_addr()
|
||||||
<< " distance: " << distance_exp(m_target, o->id());
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
|
<< " type: " << name()
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
return;
|
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
|
TORRENT_LOG(traversal) << "[" << this << "] ADD id: " << id
|
||||||
<< " address: " << addr
|
<< " address: " << addr
|
||||||
<< " distance: " << distance_exp(m_target, id)
|
<< " distance: " << distance_exp(m_target, id)
|
||||||
<< " invoke-count: " << m_invoke_count;
|
<< " invoke-count: " << m_invoke_count
|
||||||
|
<< " type: " << name()
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
i = m_results.insert(i, o);
|
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())
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
<< " addr: " << o->target_ep()
|
<< " addr: " << o->target_ep()
|
||||||
<< " branch-factor: " << m_branch_factor
|
<< " branch-factor: " << m_branch_factor
|
||||||
<< " invoke-count: " << m_invoke_count;
|
<< " invoke-count: " << m_invoke_count
|
||||||
|
<< " type: " << name()
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -285,7 +293,9 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
||||||
<< " distance: " << distance_exp(m_target, o->id())
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
<< " addr: " << o->target_ep()
|
<< " addr: " << o->target_ep()
|
||||||
<< " branch-factor: " << m_branch_factor
|
<< " branch-factor: " << m_branch_factor
|
||||||
<< " invoke-count: " << m_invoke_count;
|
<< " invoke-count: " << m_invoke_count
|
||||||
|
<< " type: " << name()
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
// don't tell the routing table about
|
// don't tell the routing table about
|
||||||
// node ids that we just generated ourself
|
// node ids that we just generated ourself
|
||||||
|
@ -322,7 +332,8 @@ void traversal_algorithm::done()
|
||||||
<< results_target
|
<< results_target
|
||||||
<< " id: " << o->id()
|
<< " id: " << o->id()
|
||||||
<< " distance: " << distance_exp(m_target, o->id())
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
<< " address: " << o->target_ep();
|
<< " address: " << o->target_ep()
|
||||||
|
;
|
||||||
--results_target;
|
--results_target;
|
||||||
int dist = distance_exp(m_target, o->id());
|
int dist = distance_exp(m_target, o->id());
|
||||||
if (dist < closest_target) closest_target = dist;
|
if (dist < closest_target) closest_target = dist;
|
||||||
|
@ -330,7 +341,9 @@ void traversal_algorithm::done()
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_LOG(traversal) << "[" << this << "] COMPLETED "
|
TORRENT_LOG(traversal) << "[" << this << "] COMPLETED "
|
||||||
<< "distance: " << closest_target;
|
<< "distance: " << closest_target
|
||||||
|
<< " type: " << name()
|
||||||
|
;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// delete all our references to the observer objects so
|
// delete all our references to the observer objects so
|
||||||
|
@ -393,6 +406,7 @@ bool traversal_algorithm::add_requests()
|
||||||
<< " invoke-count: " << m_invoke_count
|
<< " invoke-count: " << m_invoke_count
|
||||||
<< " branch-factor: " << m_branch_factor
|
<< " branch-factor: " << m_branch_factor
|
||||||
<< " distance: " << distance_exp(m_target, (*i)->id())
|
<< " distance: " << distance_exp(m_target, (*i)->id())
|
||||||
|
<< " type: " << name()
|
||||||
;
|
;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -902,7 +902,7 @@ namespace libtorrent
|
||||||
sha1_hash ret = hasher(&buf[0], buf.size()).final();
|
sha1_hash ret = hasher(&buf[0], buf.size()).final();
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
TORRENT_ASYNC_CALL1(dht_put_item, data);
|
TORRENT_ASYNC_CALL2(dht_put_item, data, ret);
|
||||||
#endif
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5693,6 +5693,12 @@ retry:
|
||||||
void session_impl::start_dht()
|
void session_impl::start_dht()
|
||||||
{ start_dht(m_dht_state); }
|
{ 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)
|
void session_impl::start_dht(entry const& startup_state)
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
@ -5706,7 +5712,7 @@ retry:
|
||||||
m_dht->add_router_node(*i);
|
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());
|
m_udp_socket.subscribe(m_dht.get());
|
||||||
}
|
}
|
||||||
|
@ -5806,15 +5812,20 @@ retry:
|
||||||
, this, _1), salt);
|
, this, _1), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nop() {}
|
void on_dht_put(alert_manager& alerts, sha1_hash target)
|
||||||
|
|
||||||
void session_impl::dht_put_item(entry data)
|
|
||||||
{
|
{
|
||||||
if (!m_dht) return;
|
if (alerts.should_post<dht_put_alert>())
|
||||||
m_dht->put_item(data, boost::bind(&nop));
|
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::function<void(entry&, boost::array<char,64>&
|
||||||
, boost::uint64_t&, std::string const&)> cb)
|
, boost::uint64_t&, std::string const&)> cb)
|
||||||
{
|
{
|
||||||
|
@ -5825,6 +5836,9 @@ 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.post_alert(dht_put_alert(pk, sig, salt, seq));
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
void session_impl::dht_put_mutable_item(boost::array<char, 32> key
|
||||||
|
@ -5833,7 +5847,8 @@ 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, _1, cb), salt);
|
m_dht->put_item(key.data(), boost::bind(&put_mutable_callback
|
||||||
|
, boost::ref(m_alerts), _1, cb), salt);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,4 +18,5 @@ project tools
|
||||||
|
|
||||||
exe parse_hash_fails : parse_hash_fails.cpp ;
|
exe parse_hash_fails : parse_hash_fails.cpp ;
|
||||||
exe parse_request_log : parse_request_log.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