2006-08-01 17:27:08 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2006, 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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2007-03-17 18:15:16 +01:00
|
|
|
#include "libtorrent/pch.hpp"
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#include <fstream>
|
|
|
|
#include <set>
|
|
|
|
#include <numeric>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <boost/bind.hpp>
|
|
|
|
#include <boost/ref.hpp>
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/filesystem/operations.hpp>
|
|
|
|
|
|
|
|
#include "libtorrent/kademlia/node.hpp"
|
|
|
|
#include "libtorrent/kademlia/node_id.hpp"
|
|
|
|
#include "libtorrent/kademlia/traversal_algorithm.hpp"
|
|
|
|
#include "libtorrent/kademlia/dht_tracker.hpp"
|
2008-11-11 18:51:02 +01:00
|
|
|
#include "libtorrent/kademlia/msg.hpp"
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-09-20 19:42:25 +02:00
|
|
|
#include "libtorrent/aux_/session_impl.hpp"
|
2006-08-01 17:27:08 +02:00
|
|
|
#include "libtorrent/socket.hpp"
|
2009-09-16 05:46:36 +02:00
|
|
|
#include "libtorrent/socket_io.hpp"
|
2006-08-01 17:27:08 +02:00
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/io.hpp"
|
|
|
|
#include "libtorrent/version.hpp"
|
2008-05-19 09:36:04 +02:00
|
|
|
#include "libtorrent/escape_string.hpp"
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
using boost::ref;
|
|
|
|
using boost::lexical_cast;
|
|
|
|
using libtorrent::dht::node_impl;
|
|
|
|
using libtorrent::dht::node_id;
|
|
|
|
using libtorrent::dht::packet_t;
|
|
|
|
using libtorrent::dht::msg;
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2007-05-14 19:49:36 +02:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
key_refresh = 5 // generate a new write token key every 5 minutes
|
|
|
|
};
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
namespace
|
|
|
|
{
|
2006-08-06 18:36:00 +02:00
|
|
|
const int tick_period = 1; // minutes
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
struct count_peers
|
|
|
|
{
|
|
|
|
int& count;
|
|
|
|
count_peers(int& c): count(c) {}
|
|
|
|
void operator()(std::pair<libtorrent::dht::node_id
|
|
|
|
, libtorrent::dht::torrent_entry> const& t)
|
|
|
|
{
|
2009-08-30 09:38:52 +02:00
|
|
|
count += t.second.peers.size();
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-11-11 18:51:02 +01:00
|
|
|
template <class EndpointType>
|
|
|
|
void read_endpoint_list(libtorrent::entry const* n, std::vector<EndpointType>& epl)
|
2006-09-21 20:22:26 +02:00
|
|
|
{
|
|
|
|
using namespace libtorrent;
|
2008-10-21 10:45:42 +02:00
|
|
|
if (n->type() != entry::list_t) return;
|
2006-09-21 20:22:26 +02:00
|
|
|
entry::list_type const& contacts = n->list();
|
|
|
|
for (entry::list_type::const_iterator i = contacts.begin()
|
|
|
|
, end(contacts.end()); i != end; ++i)
|
|
|
|
{
|
2008-10-21 10:45:42 +02:00
|
|
|
if (i->type() != entry::string_t) return;
|
2006-09-21 20:22:26 +02:00
|
|
|
std::string const& p = i->string();
|
|
|
|
if (p.size() < 6) continue;
|
|
|
|
std::string::const_iterator in = p.begin();
|
|
|
|
if (p.size() == 6)
|
|
|
|
epl.push_back(read_v4_endpoint<EndpointType>(in));
|
2009-04-04 18:59:53 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2006-09-21 20:22:26 +02:00
|
|
|
else if (p.size() == 18)
|
|
|
|
epl.push_back(read_v6_endpoint<EndpointType>(in));
|
2009-04-04 18:59:53 +02:00
|
|
|
#endif
|
2006-09-21 20:22:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace libtorrent { namespace dht
|
|
|
|
{
|
2007-02-25 10:42:43 +01:00
|
|
|
|
2009-09-25 18:32:02 +02:00
|
|
|
void incoming_error(entry& e, char const* msg);
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
int g_az_message_input = 0;
|
|
|
|
int g_ut_message_input = 0;
|
|
|
|
int g_lt_message_input = 0;
|
|
|
|
int g_mp_message_input = 0;
|
|
|
|
int g_gr_message_input = 0;
|
|
|
|
int g_mo_message_input = 0;
|
|
|
|
int g_unknown_message_input = 0;
|
|
|
|
#endif
|
|
|
|
|
2007-02-25 10:42:43 +01:00
|
|
|
void intrusive_ptr_add_ref(dht_tracker const* c)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(c != 0);
|
|
|
|
TORRENT_ASSERT(c->m_refs >= 0);
|
2007-02-25 10:42:43 +01:00
|
|
|
++c->m_refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intrusive_ptr_release(dht_tracker const* c)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(c != 0);
|
|
|
|
TORRENT_ASSERT(c->m_refs > 0);
|
2007-02-25 10:42:43 +01:00
|
|
|
if (--c->m_refs == 0)
|
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
std::string parse_dht_client(lazy_entry const& e)
|
|
|
|
{
|
|
|
|
lazy_entry const* ver = e.dict_find_string("v");
|
|
|
|
if (!ver) return "generic";
|
|
|
|
std::string const& client = ver->string_value();
|
|
|
|
if (client.size() < 2)
|
|
|
|
{
|
|
|
|
++g_unknown_message_input;
|
|
|
|
return client;
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "Az"))
|
|
|
|
{
|
|
|
|
++g_az_message_input;
|
|
|
|
return "Azureus";
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "UT"))
|
|
|
|
{
|
|
|
|
++g_ut_message_input;
|
|
|
|
return "uTorrent";
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "LT"))
|
|
|
|
{
|
|
|
|
++g_lt_message_input;
|
|
|
|
return "libtorrent";
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "MP"))
|
|
|
|
{
|
|
|
|
++g_mp_message_input;
|
|
|
|
return "MooPolice";
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "GR"))
|
|
|
|
{
|
|
|
|
++g_gr_message_input;
|
|
|
|
return "GetRight";
|
|
|
|
}
|
|
|
|
else if (std::equal(client.begin(), client.begin() + 2, "MO"))
|
|
|
|
{
|
|
|
|
++g_mo_message_input;
|
|
|
|
return "Mono Torrent";
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++g_unknown_message_input;
|
|
|
|
return client;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_DEFINE_LOG(dht_tracker)
|
|
|
|
#endif
|
|
|
|
|
2008-11-11 18:51:02 +01:00
|
|
|
boost::optional<node_id> extract_node_id(lazy_entry const* e)
|
|
|
|
{
|
|
|
|
if (e == 0 || e->type() != lazy_entry::dict_t) return boost::optional<node_id>();
|
|
|
|
lazy_entry const* nid = e->dict_find_string("node-id");
|
|
|
|
if (nid == 0 || nid->string_length() != 20) return boost::optional<node_id>();
|
|
|
|
return boost::optional<node_id>(node_id(nid->string_ptr()));
|
|
|
|
}
|
|
|
|
|
2008-11-11 09:33:34 +01:00
|
|
|
boost::optional<node_id> extract_node_id(entry const* e)
|
|
|
|
{
|
|
|
|
if (e == 0 || e->type() != entry::dictionary_t) return boost::optional<node_id>();
|
|
|
|
entry const* nid = e->find_key("node-id");
|
|
|
|
if (nid == 0 || nid->type() != entry::string_t || nid->string().length() != 20)
|
|
|
|
return boost::optional<node_id>();
|
|
|
|
return boost::optional<node_id>(node_id(nid->string().c_str()));
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
void send_callback(void* userdata, entry const& e, udp::endpoint const& addr, int flags)
|
|
|
|
{
|
|
|
|
dht_tracker* self = (dht_tracker*)userdata;
|
|
|
|
self->send_packet(e, addr, flags);
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
// class that puts the networking and the kademlia node in a single
|
|
|
|
// unit and connecting them together.
|
2008-11-08 18:40:06 +01:00
|
|
|
dht_tracker::dht_tracker(libtorrent::aux::session_impl& ses, rate_limited_udp_socket& sock
|
2008-11-11 09:33:34 +01:00
|
|
|
, dht_settings const& settings, entry const* state)
|
2009-09-20 02:23:36 +02:00
|
|
|
: m_dht(ses, &send_callback, settings, extract_node_id(state), this)
|
2008-09-20 19:42:25 +02:00
|
|
|
, m_ses(ses)
|
2007-12-09 05:15:24 +01:00
|
|
|
, m_sock(sock)
|
2007-05-14 19:49:36 +02:00
|
|
|
, m_last_new_key(time_now() - minutes(key_refresh))
|
2007-12-09 05:15:24 +01:00
|
|
|
, m_timer(sock.get_io_service())
|
|
|
|
, m_connection_timer(sock.get_io_service())
|
|
|
|
, m_refresh_timer(sock.get_io_service())
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_settings(settings)
|
|
|
|
, m_refresh_bucket(160)
|
2008-03-24 05:38:43 +01:00
|
|
|
, m_abort(false)
|
2007-12-09 05:15:24 +01:00
|
|
|
, m_host_resolver(sock.get_io_service())
|
2008-11-10 05:16:18 +01:00
|
|
|
, m_sent_bytes(0)
|
|
|
|
, m_received_bytes(0)
|
2007-02-25 10:42:43 +01:00
|
|
|
, m_refs(0)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
using boost::bind;
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
m_counter = 0;
|
|
|
|
std::fill_n(m_replies_bytes_sent, 5, 0);
|
|
|
|
std::fill_n(m_queries_bytes_received, 5, 0);
|
|
|
|
std::fill_n(m_replies_sent, 5, 0);
|
|
|
|
std::fill_n(m_queries_received, 5, 0);
|
|
|
|
m_announces = 0;
|
|
|
|
m_failed_announces = 0;
|
|
|
|
m_total_message_input = 0;
|
2006-08-06 18:36:00 +02:00
|
|
|
m_total_in_bytes = 0;
|
|
|
|
m_total_out_bytes = 0;
|
|
|
|
m_queries_out_bytes = 0;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
// turns on and off individual components' logging
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
// rpc_log().enable(false);
|
2008-12-23 21:04:12 +01:00
|
|
|
// node_log().enable(false);
|
2008-11-11 18:51:02 +01:00
|
|
|
traversal_log().enable(false);
|
2006-08-01 17:27:08 +02:00
|
|
|
// dht_tracker_log.enable(false);
|
|
|
|
|
2008-11-11 18:51:02 +01:00
|
|
|
TORRENT_LOG(dht_tracker) << "starting DHT tracker with node id: " << m_dht.nid();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2008-09-02 08:37:40 +02:00
|
|
|
void dht_tracker::start(entry const& bootstrap)
|
|
|
|
{
|
2006-08-01 17:27:08 +02:00
|
|
|
std::vector<udp::endpoint> initial_nodes;
|
|
|
|
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-08-01 17:27:08 +02:00
|
|
|
if (bootstrap.type() == entry::dictionary_t)
|
|
|
|
{
|
2009-05-07 09:01:36 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2006-09-21 20:22:26 +02:00
|
|
|
try
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2009-05-07 09:01:36 +02:00
|
|
|
#endif
|
2006-09-21 20:22:26 +02:00
|
|
|
if (entry const* nodes = bootstrap.find_key("nodes"))
|
|
|
|
read_endpoint_list<udp::endpoint>(nodes, initial_nodes);
|
2009-05-07 09:01:36 +02:00
|
|
|
#ifndef BOOST_NO_EXCEPTIONS
|
2006-09-21 20:22:26 +02:00
|
|
|
} catch (std::exception&) {}
|
2009-05-07 09:01:36 +02:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2008-10-21 10:45:42 +02:00
|
|
|
error_code ec;
|
|
|
|
m_timer.expires_from_now(seconds(1), ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_timer.async_wait(bind(&dht_tracker::tick, self(), _1));
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-10-21 10:45:42 +02:00
|
|
|
m_connection_timer.expires_from_now(seconds(10), ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_connection_timer.async_wait(
|
|
|
|
bind(&dht_tracker::connection_timeout, self(), _1));
|
2006-08-06 18:36:00 +02:00
|
|
|
|
2008-10-21 10:45:42 +02:00
|
|
|
m_refresh_timer.expires_from_now(seconds(5), ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_refresh_timer.async_wait(bind(&dht_tracker::refresh_timeout, self(), _1));
|
2009-09-20 02:23:36 +02:00
|
|
|
m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, self(), _1));
|
2007-02-25 10:42:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::stop()
|
|
|
|
{
|
2008-03-24 05:38:43 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
m_abort = true;
|
2008-10-21 10:45:42 +02:00
|
|
|
error_code ec;
|
|
|
|
m_timer.cancel(ec);
|
|
|
|
m_connection_timer.cancel(ec);
|
|
|
|
m_refresh_timer.cancel(ec);
|
2007-11-11 20:09:29 +01:00
|
|
|
m_host_resolver.cancel();
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2006-09-05 01:22:21 +02:00
|
|
|
void dht_tracker::dht_status(session_status& s)
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2008-09-20 19:42:25 +02:00
|
|
|
m_dht.status(s);
|
2006-09-05 01:22:21 +02:00
|
|
|
}
|
|
|
|
|
2008-11-02 11:01:04 +01:00
|
|
|
void dht_tracker::network_stats(int& sent, int& received)
|
|
|
|
{
|
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
sent = m_sent_bytes;
|
|
|
|
received = m_received_bytes;
|
|
|
|
m_sent_bytes = 0;
|
|
|
|
m_received_bytes = 0;
|
|
|
|
}
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void dht_tracker::connection_timeout(error_code const& e)
|
2006-08-06 18:36:00 +02:00
|
|
|
{
|
2008-03-24 05:38:43 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
if (e || m_abort) return;
|
|
|
|
|
2006-08-06 18:36:00 +02:00
|
|
|
time_duration d = m_dht.connection_timeout();
|
2008-10-21 19:10:11 +02:00
|
|
|
error_code ec;
|
|
|
|
m_connection_timer.expires_from_now(d, ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_connection_timer.async_wait(bind(&dht_tracker::connection_timeout, self(), _1));
|
2006-08-06 18:36:00 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void dht_tracker::refresh_timeout(error_code const& e)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-03-24 05:38:43 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
if (e || m_abort) return;
|
|
|
|
|
2006-08-06 18:36:00 +02:00
|
|
|
time_duration d = m_dht.refresh_timeout();
|
2008-10-21 19:10:11 +02:00
|
|
|
error_code ec;
|
|
|
|
m_refresh_timer.expires_from_now(d, ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_refresh_timer.async_wait(
|
|
|
|
bind(&dht_tracker::refresh_timeout, self(), _1));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void dht_tracker::tick(error_code const& e)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-03-24 05:38:43 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
if (e || m_abort) return;
|
|
|
|
|
2008-10-21 19:10:11 +02:00
|
|
|
error_code ec;
|
|
|
|
m_timer.expires_from_now(minutes(tick_period), ec);
|
2007-12-09 05:15:24 +01:00
|
|
|
m_timer.async_wait(bind(&dht_tracker::tick, self(), _1));
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2007-05-14 19:49:36 +02:00
|
|
|
ptime now = time_now();
|
|
|
|
if (now - m_last_new_key > minutes(key_refresh))
|
|
|
|
{
|
|
|
|
m_last_new_key = now;
|
|
|
|
m_dht.new_write_key();
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2008-12-23 21:04:12 +01:00
|
|
|
TORRENT_LOG(dht_tracker) << " *** new write key";
|
2007-05-14 19:49:36 +02:00
|
|
|
#endif
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
static bool first = true;
|
|
|
|
|
2008-11-12 04:56:56 +01:00
|
|
|
std::ofstream st("dht_routing_table_state.txt", std::ios_base::trunc);
|
2006-08-01 17:27:08 +02:00
|
|
|
m_dht.print_state(st);
|
|
|
|
|
|
|
|
// count torrents
|
|
|
|
int torrents = std::distance(m_dht.begin_data(), m_dht.end_data());
|
|
|
|
|
|
|
|
// count peers
|
|
|
|
int peers = 0;
|
|
|
|
std::for_each(m_dht.begin_data(), m_dht.end_data(), count_peers(peers));
|
|
|
|
|
2009-01-01 19:29:42 +01:00
|
|
|
std::ofstream pc("dht_stats.log", first ? std::ios_base::trunc : std::ios_base::app);
|
2006-08-01 17:27:08 +02:00
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
first = false;
|
2007-04-10 09:52:58 +02:00
|
|
|
pc << "\n\n ***** starting log at " << time_now_string() << " *****\n\n"
|
2006-08-01 17:27:08 +02:00
|
|
|
<< "minute:active nodes:passive nodes"
|
2008-12-23 19:38:48 +01:00
|
|
|
":ping replies sent:ping queries recvd"
|
|
|
|
":ping replies bytes sent:ping queries bytes recvd"
|
|
|
|
":find_node replies sent:find_node queries recv"
|
2006-08-01 17:27:08 +02:00
|
|
|
":find_node replies bytes sent:find_node queries bytes recv"
|
2008-12-23 19:38:48 +01:00
|
|
|
":get_peers replies sent:get_peers queries recvd"
|
2006-08-01 17:27:08 +02:00
|
|
|
":get_peers replies bytes sent:get_peers queries bytes recv"
|
2008-12-23 19:38:48 +01:00
|
|
|
":announce_peer replies sent:announce_peer queries recvd"
|
2006-08-01 17:27:08 +02:00
|
|
|
":announce_peer replies bytes sent:announce_peer queries bytes recv"
|
2008-12-23 19:38:48 +01:00
|
|
|
":error replies sent:error queries recvd"
|
2006-08-01 17:27:08 +02:00
|
|
|
":error replies bytes sent:error queries bytes recv"
|
|
|
|
":num torrents:num peers:announces per min"
|
|
|
|
":failed announces per min:total msgs per min"
|
2008-12-23 19:38:48 +01:00
|
|
|
":az msgs per min:ut msgs per min:lt msgs per min:mp msgs per min"
|
|
|
|
":gr msgs per min:mo msgs per min:bytes in per sec:bytes out per sec"
|
2006-08-06 18:36:00 +02:00
|
|
|
":queries out bytes per sec\n\n";
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int active;
|
|
|
|
int passive;
|
|
|
|
boost::tie(active, passive) = m_dht.size();
|
|
|
|
pc << (m_counter * tick_period)
|
|
|
|
<< "\t" << active
|
|
|
|
<< "\t" << passive;
|
|
|
|
for (int i = 0; i < 5; ++i)
|
|
|
|
pc << "\t" << (m_replies_sent[i] / float(tick_period))
|
|
|
|
<< "\t" << (m_queries_received[i] / float(tick_period))
|
|
|
|
<< "\t" << (m_replies_bytes_sent[i] / float(tick_period*60))
|
|
|
|
<< "\t" << (m_queries_bytes_received[i] / float(tick_period*60));
|
|
|
|
|
|
|
|
pc << "\t" << torrents
|
|
|
|
<< "\t" << peers
|
|
|
|
<< "\t" << m_announces / float(tick_period)
|
|
|
|
<< "\t" << m_failed_announces / float(tick_period)
|
|
|
|
<< "\t" << (m_total_message_input / float(tick_period))
|
2009-09-20 02:23:36 +02:00
|
|
|
<< "\t" << (g_az_message_input / float(tick_period))
|
|
|
|
<< "\t" << (g_ut_message_input / float(tick_period))
|
|
|
|
<< "\t" << (g_lt_message_input / float(tick_period))
|
|
|
|
<< "\t" << (g_mp_message_input / float(tick_period))
|
|
|
|
<< "\t" << (g_gr_message_input / float(tick_period))
|
|
|
|
<< "\t" << (g_mo_message_input / float(tick_period))
|
2006-08-06 18:36:00 +02:00
|
|
|
<< "\t" << (m_total_in_bytes / float(tick_period*60))
|
|
|
|
<< "\t" << (m_total_out_bytes / float(tick_period*60))
|
|
|
|
<< "\t" << (m_queries_out_bytes / float(tick_period*60))
|
2006-08-01 17:27:08 +02:00
|
|
|
<< std::endl;
|
|
|
|
++m_counter;
|
|
|
|
std::fill_n(m_replies_bytes_sent, 5, 0);
|
|
|
|
std::fill_n(m_queries_bytes_received, 5, 0);
|
|
|
|
std::fill_n(m_replies_sent, 5, 0);
|
|
|
|
std::fill_n(m_queries_received, 5, 0);
|
|
|
|
m_announces = 0;
|
|
|
|
m_failed_announces = 0;
|
|
|
|
m_total_message_input = 0;
|
2009-09-20 02:23:36 +02:00
|
|
|
g_az_message_input = 0;
|
|
|
|
g_ut_message_input = 0;
|
|
|
|
g_lt_message_input = 0;
|
|
|
|
g_mp_message_input = 0;
|
|
|
|
g_gr_message_input = 0;
|
|
|
|
g_mo_message_input = 0;
|
|
|
|
g_unknown_message_input = 0;
|
2006-08-06 18:36:00 +02:00
|
|
|
m_total_in_bytes = 0;
|
|
|
|
m_total_out_bytes = 0;
|
|
|
|
m_queries_out_bytes = 0;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::announce(sha1_hash const& ih, int listen_port
|
2008-12-23 21:04:12 +01:00
|
|
|
, boost::function<void(std::vector<tcp::endpoint> const&)> f)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-08-01 17:27:08 +02:00
|
|
|
m_dht.announce(ih, listen_port, f);
|
|
|
|
}
|
|
|
|
|
2008-05-08 02:22:17 +02:00
|
|
|
|
|
|
|
void dht_tracker::on_unreachable(udp::endpoint const& ep)
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2008-05-08 02:22:17 +02:00
|
|
|
m_dht.unreachable(ep);
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
// translate bittorrent kademlia message into the generice kademlia message
|
|
|
|
// used by the library
|
2007-12-09 05:15:24 +01:00
|
|
|
void dht_tracker::on_receive(udp::endpoint const& ep, char const* buf, int bytes_transferred)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
|
|
|
// account for IP and UDP overhead
|
2008-11-14 21:51:49 +01:00
|
|
|
m_received_bytes += bytes_transferred + (ep.address().is_v6() ? 48 : 28);
|
2008-09-20 19:42:25 +02:00
|
|
|
|
2007-12-04 03:53:10 +01:00
|
|
|
node_ban_entry* match = 0;
|
|
|
|
node_ban_entry* min = m_ban_nodes;
|
|
|
|
ptime now = time_now();
|
|
|
|
for (node_ban_entry* i = m_ban_nodes; i < m_ban_nodes + num_ban_nodes; ++i)
|
|
|
|
{
|
2009-05-13 23:07:51 +02:00
|
|
|
if (i->src == ep.address())
|
2007-12-04 03:53:10 +01:00
|
|
|
{
|
|
|
|
match = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i->count < min->count) min = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match)
|
|
|
|
{
|
|
|
|
++match->count;
|
|
|
|
if (match->count >= 20)
|
|
|
|
{
|
|
|
|
if (now < match->limit)
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
if (match->count == 20)
|
|
|
|
{
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << " BANNING PEER [ ip: "
|
2008-05-18 07:09:11 +02:00
|
|
|
<< ep << " time: " << total_milliseconds((now - match->limit) + seconds(5)) / 1000.f
|
|
|
|
<< " count: " << match->count << " ]";
|
2007-12-04 03:53:10 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// we've received 20 messages in less than 5 seconds from
|
|
|
|
// this node. Ignore it until it's silent for 5 minutes
|
|
|
|
match->limit = now + minutes(5);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// we got 50 messages from this peer, but it was in
|
|
|
|
// more than 5 seconds. Reset the counter and the timer
|
|
|
|
match->count = 0;
|
|
|
|
match->limit = now + seconds(5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
min->count = 1;
|
|
|
|
min->limit = now + seconds(5);
|
2009-05-13 23:07:51 +02:00
|
|
|
min->src = ep.address();
|
2007-12-04 03:53:10 +01:00
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
++m_total_message_input;
|
2006-08-06 18:36:00 +02:00
|
|
|
m_total_in_bytes += bytes_transferred;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
|
2008-10-21 19:10:11 +02:00
|
|
|
using libtorrent::entry;
|
|
|
|
using libtorrent::bdecode;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-10-21 19:10:11 +02:00
|
|
|
TORRENT_ASSERT(bytes_transferred > 0);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-11-11 18:51:02 +01:00
|
|
|
lazy_entry e;
|
|
|
|
int ret = lazy_bdecode(buf, buf + bytes_transferred, e);
|
|
|
|
if (ret != 0)
|
2008-10-21 19:10:11 +02:00
|
|
|
{
|
2009-09-20 17:21:31 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: Invalid bencoding";
|
2009-09-20 17:21:31 +02:00
|
|
|
#endif
|
2008-10-21 19:10:11 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
libtorrent::dht::msg m = {e, ep};
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2008-11-11 18:51:02 +01:00
|
|
|
if (e.type() != lazy_entry::dict_t)
|
2008-10-21 19:10:11 +02:00
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << "<== " << ep << " ERROR: not a dictionary: "
|
|
|
|
<< print_entry(e, true);
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
2009-09-20 02:23:36 +02:00
|
|
|
entry r;
|
2009-09-26 00:03:35 +02:00
|
|
|
libtorrent::dht::incoming_error(r, "message is not a dictionary");
|
2009-09-20 02:23:36 +02:00
|
|
|
send_packet(r, ep, 0);
|
2008-10-21 19:10:11 +02:00
|
|
|
return;
|
2008-11-09 01:37:03 +01:00
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
parse_dht_client(e);
|
|
|
|
TORRENT_LOG(dht_tracker) << "<== " << ep << " " << print_entry(e, true);
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
|
2008-10-21 19:10:11 +02:00
|
|
|
m_dht.incoming(m);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
entry dht_tracker::state() const
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-08-01 17:27:08 +02:00
|
|
|
entry ret(entry::dictionary_t);
|
|
|
|
{
|
2006-09-01 05:06:00 +02:00
|
|
|
entry nodes(entry::list_t);
|
2006-08-01 17:27:08 +02:00
|
|
|
for (node_impl::iterator i(m_dht.begin())
|
|
|
|
, end(m_dht.end()); i != end; ++i)
|
2006-09-01 05:06:00 +02:00
|
|
|
{
|
|
|
|
std::string node;
|
|
|
|
std::back_insert_iterator<std::string> out(node);
|
2008-11-10 03:08:42 +01:00
|
|
|
write_endpoint(udp::endpoint(i->addr, i->port), out);
|
2006-09-01 05:06:00 +02:00
|
|
|
nodes.list().push_back(entry(node));
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
bucket_t cache;
|
|
|
|
m_dht.replacement_cache(cache);
|
|
|
|
for (bucket_t::iterator i(cache.begin())
|
|
|
|
, end(cache.end()); i != end; ++i)
|
2006-09-01 05:06:00 +02:00
|
|
|
{
|
|
|
|
std::string node;
|
|
|
|
std::back_insert_iterator<std::string> out(node);
|
2008-11-10 03:08:42 +01:00
|
|
|
write_endpoint(udp::endpoint(i->addr, i->port), out);
|
2006-09-01 05:06:00 +02:00
|
|
|
nodes.list().push_back(entry(node));
|
|
|
|
}
|
|
|
|
if (!nodes.list().empty())
|
2006-08-01 17:27:08 +02:00
|
|
|
ret["nodes"] = nodes;
|
|
|
|
}
|
2008-10-21 19:10:11 +02:00
|
|
|
|
2009-04-04 11:52:25 +02:00
|
|
|
char node_id[41];
|
|
|
|
to_hex((char*)&m_dht.nid()[0], 20, node_id);
|
|
|
|
ret["node-id"] = node_id;
|
2006-08-01 17:27:08 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::add_node(udp::endpoint node)
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-08-01 17:27:08 +02:00
|
|
|
m_dht.add_node(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::add_node(std::pair<std::string, int> const& node)
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-08-01 17:27:08 +02:00
|
|
|
udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
|
2007-12-09 05:15:24 +01:00
|
|
|
m_host_resolver.async_resolve(q,
|
|
|
|
bind(&dht_tracker::on_name_lookup, self(), _1, _2));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
2006-09-27 19:20:18 +02:00
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void dht_tracker::on_name_lookup(error_code const& e
|
2008-10-21 19:10:11 +02:00
|
|
|
, udp::resolver::iterator host)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
if (e || host == udp::resolver::iterator()) return;
|
|
|
|
add_node(host->endpoint());
|
|
|
|
}
|
|
|
|
|
2006-09-27 19:20:18 +02:00
|
|
|
void dht_tracker::add_router_node(std::pair<std::string, int> const& node)
|
|
|
|
{
|
2008-11-02 11:01:04 +01:00
|
|
|
mutex_t::scoped_lock l(m_mutex);
|
2006-09-27 19:20:18 +02:00
|
|
|
udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
|
2007-12-09 05:15:24 +01:00
|
|
|
m_host_resolver.async_resolve(q,
|
|
|
|
bind(&dht_tracker::on_router_name_lookup, self(), _1, _2));
|
2006-09-27 19:20:18 +02:00
|
|
|
}
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void dht_tracker::on_router_name_lookup(error_code const& e
|
2008-10-21 19:10:11 +02:00
|
|
|
, udp::resolver::iterator host)
|
2006-09-27 19:20:18 +02:00
|
|
|
{
|
|
|
|
if (e || host == udp::resolver::iterator()) return;
|
|
|
|
m_dht.add_router_node(host->endpoint());
|
|
|
|
}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
void dht_tracker::on_bootstrap(std::vector<std::pair<node_entry, std::string> > const&)
|
2006-08-01 17:27:08 +02:00
|
|
|
{}
|
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
void dht_tracker::send_packet(libtorrent::entry const& e, udp::endpoint const& addr, int send_flags)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
using libtorrent::bencode;
|
|
|
|
using libtorrent::entry;
|
2008-12-23 21:04:12 +01:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
m_send_buf.clear();
|
|
|
|
bencode(std::back_inserter(m_send_buf), e);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
std::stringstream log_line;
|
|
|
|
lazy_entry print;
|
|
|
|
int ret = lazy_bdecode(&m_send_buf[0], &m_send_buf[0] + m_send_buf.size(), print);
|
|
|
|
TORRENT_ASSERT(ret == 0);
|
|
|
|
log_line << print_entry(print, true);
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2009-09-20 02:23:36 +02:00
|
|
|
if (m_sock.send(addr, &m_send_buf[0], (int)m_send_buf.size(), ec, send_flags))
|
2008-11-09 01:37:03 +01:00
|
|
|
{
|
|
|
|
// account for IP and UDP overhead
|
2009-09-20 02:23:36 +02:00
|
|
|
m_sent_bytes += m_send_buf.size() + (addr.address().is_v6() ? 48 : 28);
|
2008-09-20 19:42:25 +02:00
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2008-11-09 01:37:03 +01:00
|
|
|
m_total_out_bytes += m_send_buf.size();
|
2006-08-06 18:36:00 +02:00
|
|
|
|
2009-09-20 02:23:36 +02:00
|
|
|
if (e["y"].string() == "r")
|
2008-11-09 01:37:03 +01:00
|
|
|
{
|
2009-09-20 02:23:36 +02:00
|
|
|
// TODO: fix this stats logging
|
|
|
|
// ++m_replies_sent[e["r"]];
|
|
|
|
// m_replies_bytes_sent[e["r"]] += int(m_send_buf.size());
|
2008-11-09 01:37:03 +01:00
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
else if (e["y"].string() == "q")
|
2008-11-09 01:37:03 +01:00
|
|
|
{
|
|
|
|
m_queries_out_bytes += m_send_buf.size();
|
|
|
|
}
|
2009-09-20 02:23:36 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << "==> " << addr << " " << log_line.str();
|
2008-11-09 10:02:06 +01:00
|
|
|
#endif
|
2006-08-06 18:36:00 +02:00
|
|
|
}
|
2008-11-10 04:08:29 +01:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2009-09-20 02:23:36 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
TORRENT_LOG(dht_tracker) << "==> " << addr << " DROPPED " << log_line.str();
|
|
|
|
}
|
2008-11-10 04:08:29 +01:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|