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"
|
|
|
|
|
|
|
|
#include "libtorrent/socket.hpp"
|
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/io.hpp"
|
|
|
|
#include "libtorrent/version.hpp"
|
|
|
|
|
|
|
|
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 libtorrent::dht::packet_iterator;
|
|
|
|
namespace messages = libtorrent::dht::messages;
|
|
|
|
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
|
|
|
using asio::ip::udp;
|
|
|
|
typedef asio::ip::address_v4 address;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
count += std::distance(t.second.peers.begin()
|
|
|
|
, t.second.peers.end());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
boost::optional<node_id> read_id(libtorrent::entry const& d)
|
|
|
|
{
|
|
|
|
using namespace libtorrent;
|
|
|
|
using libtorrent::dht::node_id;
|
|
|
|
|
|
|
|
if (d.type() != entry::dictionary_t) return boost::optional<node_id>();
|
|
|
|
entry const* nid = d.find_key("node-id");
|
|
|
|
if (!nid
|
|
|
|
|| nid->type() != entry::string_t
|
|
|
|
|| nid->string().length() != 40)
|
|
|
|
return boost::optional<node_id>();
|
|
|
|
return boost::optional<node_id>(
|
|
|
|
boost::lexical_cast<node_id>(nid->string()));
|
|
|
|
}
|
2006-09-21 20:22:26 +02:00
|
|
|
|
|
|
|
template <class EndpointType>
|
|
|
|
void read_endpoint_list(libtorrent::entry const* n, std::vector<EndpointType>& epl)
|
|
|
|
{
|
|
|
|
using namespace libtorrent;
|
|
|
|
entry::list_type const& contacts = n->list();
|
|
|
|
for (entry::list_type::const_iterator i = contacts.begin()
|
|
|
|
, end(contacts.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
else if (p.size() == 18)
|
|
|
|
epl.push_back(read_v6_endpoint<EndpointType>(in));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace libtorrent { namespace dht
|
|
|
|
{
|
2007-02-25 10:42:43 +01:00
|
|
|
|
|
|
|
void intrusive_ptr_add_ref(dht_tracker const* c)
|
|
|
|
{
|
|
|
|
assert(c != 0);
|
2007-03-02 22:40:18 +01:00
|
|
|
assert(c->m_refs >= 0);
|
2007-02-25 10:42:43 +01:00
|
|
|
++c->m_refs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void intrusive_ptr_release(dht_tracker const* c)
|
|
|
|
{
|
|
|
|
assert(c != 0);
|
2007-03-02 22:40:18 +01:00
|
|
|
assert(c->m_refs > 0);
|
2007-02-25 10:42:43 +01:00
|
|
|
if (--c->m_refs == 0)
|
|
|
|
delete c;
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_DEFINE_LOG(dht_tracker)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// class that puts the networking and the kademlia node in a single
|
|
|
|
// unit and connecting them together.
|
2006-12-15 18:47:21 +01:00
|
|
|
dht_tracker::dht_tracker(asio::io_service& ios, dht_settings const& settings
|
2006-08-30 02:09:58 +02:00
|
|
|
, asio::ip::address listen_interface, entry const& bootstrap)
|
2006-12-15 18:47:21 +01:00
|
|
|
: m_strand(ios)
|
|
|
|
, m_socket(ios, udp::endpoint(listen_interface, settings.service_port))
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_dht(bind(&dht_tracker::send_packet, this, _1), settings
|
|
|
|
, read_id(bootstrap))
|
|
|
|
, m_buffer(0)
|
2007-05-14 19:49:36 +02:00
|
|
|
, m_last_new_key(time_now() - minutes(key_refresh))
|
2006-12-15 18:47:21 +01:00
|
|
|
, m_timer(ios)
|
|
|
|
, m_connection_timer(ios)
|
|
|
|
, m_refresh_timer(ios)
|
2006-08-01 17:27:08 +02:00
|
|
|
, m_settings(settings)
|
|
|
|
, m_refresh_bucket(160)
|
2006-12-15 18:47:21 +01:00
|
|
|
, m_host_resolver(ios)
|
2007-02-25 10:42:43 +01:00
|
|
|
, m_refs(0)
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
using boost::bind;
|
|
|
|
|
|
|
|
m_in_buf[0].resize(1000);
|
|
|
|
m_in_buf[1].resize(1000);
|
|
|
|
#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;
|
|
|
|
m_ut_message_input = 0;
|
|
|
|
m_lt_message_input = 0;
|
|
|
|
m_mp_message_input = 0;
|
|
|
|
m_gr_message_input = 0;
|
2007-03-02 19:40:02 +01:00
|
|
|
m_mo_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
|
|
|
|
|
|
|
|
// rpc_log().enable(false);
|
|
|
|
// node_log().enable(false);
|
|
|
|
// traversal_log().enable(false);
|
|
|
|
// dht_tracker_log.enable(false);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
std::vector<udp::endpoint> initial_nodes;
|
|
|
|
|
|
|
|
if (bootstrap.type() == entry::dictionary_t)
|
|
|
|
{
|
2006-09-21 20:22:26 +02:00
|
|
|
try
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
2006-09-21 20:22:26 +02:00
|
|
|
if (entry const* nodes = bootstrap.find_key("nodes"))
|
|
|
|
read_endpoint_list<udp::endpoint>(nodes, initial_nodes);
|
|
|
|
} catch (std::exception&) {}
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
|
|
|
|
, m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
|
2007-02-25 10:42:43 +01:00
|
|
|
, m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
|
2006-08-01 17:27:08 +02:00
|
|
|
m_timer.expires_from_now(seconds(1));
|
2007-02-25 10:42:43 +01:00
|
|
|
m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1)));
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2006-08-06 18:36:00 +02:00
|
|
|
m_connection_timer.expires_from_now(seconds(10));
|
2006-12-15 18:47:21 +01:00
|
|
|
m_connection_timer.async_wait(m_strand.wrap(
|
2007-02-25 10:42:43 +01:00
|
|
|
bind(&dht_tracker::connection_timeout, self(), _1)));
|
2006-08-06 18:36:00 +02:00
|
|
|
|
2007-05-12 03:52:25 +02:00
|
|
|
m_refresh_timer.expires_from_now(seconds(5));
|
2007-02-25 10:42:43 +01:00
|
|
|
m_refresh_timer.async_wait(m_strand.wrap(bind(&dht_tracker::refresh_timeout, self(), _1)));
|
2007-03-02 22:40:18 +01:00
|
|
|
|
|
|
|
m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, self()));
|
2007-02-25 10:42:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::stop()
|
|
|
|
{
|
|
|
|
m_timer.cancel();
|
|
|
|
m_connection_timer.cancel();
|
|
|
|
m_refresh_timer.cancel();
|
|
|
|
m_socket.close();
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
|
2006-09-05 01:22:21 +02:00
|
|
|
void dht_tracker::dht_status(session_status& s)
|
|
|
|
{
|
2006-11-28 19:18:37 +01:00
|
|
|
boost::tie(s.dht_nodes, s.dht_node_cache) = m_dht.size();
|
|
|
|
s.dht_torrents = m_dht.data_size();
|
2007-05-12 03:52:25 +02:00
|
|
|
s.dht_global_nodes = m_dht.num_global_nodes();
|
2006-09-05 01:22:21 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::connection_timeout(asio::error_code const& e)
|
2006-08-06 18:36:00 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (e) return;
|
|
|
|
time_duration d = m_dht.connection_timeout();
|
|
|
|
m_connection_timer.expires_from_now(d);
|
2007-02-25 10:42:43 +01:00
|
|
|
m_connection_timer.async_wait(m_strand.wrap(bind(&dht_tracker::connection_timeout, self(), _1)));
|
2006-08-06 18:36:00 +02:00
|
|
|
}
|
2006-11-14 01:08:16 +01:00
|
|
|
catch (std::exception& exc)
|
2006-08-06 18:36:00 +02:00
|
|
|
{
|
2007-01-04 16:44:23 +01:00
|
|
|
#ifndef NDEBUG
|
2006-11-19 16:29:58 +01:00
|
|
|
std::cerr << "exception-type: " << typeid(exc).name() << std::endl;
|
|
|
|
std::cerr << "what: " << exc.what() << std::endl;
|
2006-08-06 18:36:00 +02:00
|
|
|
assert(false);
|
2007-01-04 16:44:23 +01:00
|
|
|
#endif
|
2006-08-06 18:36:00 +02:00
|
|
|
};
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::refresh_timeout(asio::error_code const& e)
|
2006-08-01 17:27:08 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (e) return;
|
2006-08-06 18:36:00 +02:00
|
|
|
time_duration d = m_dht.refresh_timeout();
|
|
|
|
m_refresh_timer.expires_from_now(d);
|
2006-12-15 18:47:21 +01:00
|
|
|
m_refresh_timer.async_wait(m_strand.wrap(
|
2007-02-25 10:42:43 +01:00
|
|
|
bind(&dht_tracker::refresh_timeout, self(), _1)));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
2006-08-30 02:09:58 +02:00
|
|
|
void dht_tracker::rebind(asio::ip::address listen_interface, int listen_port)
|
|
|
|
{
|
|
|
|
m_socket.close();
|
2007-02-27 18:21:46 +01:00
|
|
|
udp::endpoint ep(listen_interface, listen_port);
|
|
|
|
m_socket.open(ep.protocol());
|
|
|
|
m_socket.bind(ep);
|
2006-08-30 02:09:58 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::tick(asio::error_code const& e)
|
2006-08-01 17:27:08 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (e) return;
|
|
|
|
m_timer.expires_from_now(minutes(tick_period));
|
2006-12-15 18:47:21 +01:00
|
|
|
m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, this, _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
|
|
|
|
TORRENT_LOG(dht_tracker) << time_now_string() << " new write key";
|
|
|
|
#endif
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
static bool first = true;
|
|
|
|
if (first)
|
|
|
|
{
|
|
|
|
boost::filesystem::create_directory("libtorrent_logs");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::ofstream st("libtorrent_logs/routing_table_state.txt", std::ios_base::trunc);
|
|
|
|
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));
|
|
|
|
|
|
|
|
std::ofstream pc("libtorrent_logs/dht_stats.log", std::ios_base::app);
|
|
|
|
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"
|
|
|
|
":ping replies sent:ping queries recvd:ping"
|
|
|
|
":ping replies sent:ping queries recvd:ping"
|
|
|
|
":find_node replies bytes sent:find_node queries bytes recv"
|
|
|
|
":find_node replies bytes sent:find_node queries bytes recv"
|
|
|
|
":get_peers replies sent:get_peers queries recvd:get_peers"
|
|
|
|
":get_peers replies bytes sent:get_peers queries bytes recv"
|
|
|
|
":announce_peer replies sent:announce_peer queries recvd:announce_peer"
|
|
|
|
":announce_peer replies bytes sent:announce_peer queries bytes recv"
|
|
|
|
":error replies sent:error queries recvd:error"
|
|
|
|
":error replies bytes sent:error queries bytes recv"
|
|
|
|
":num torrents:num peers:announces per min"
|
|
|
|
":failed announces per min:total msgs per min"
|
|
|
|
":ut msgs per min:lt msgs per min:mp msgs per min"
|
2006-08-06 18:36:00 +02:00
|
|
|
":gr msgs per min:bytes in per sec:bytes out per sec"
|
|
|
|
":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))
|
|
|
|
<< "\t" << (m_ut_message_input / float(tick_period))
|
|
|
|
<< "\t" << (m_lt_message_input / float(tick_period))
|
|
|
|
<< "\t" << (m_mp_message_input / float(tick_period))
|
|
|
|
<< "\t" << (m_gr_message_input / float(tick_period))
|
2007-03-02 19:40:02 +01:00
|
|
|
<< "\t" << (m_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;
|
|
|
|
m_ut_message_input = 0;
|
|
|
|
m_lt_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
|
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
void dht_tracker::announce(sha1_hash const& ih, int listen_port
|
|
|
|
, boost::function<void(std::vector<tcp::endpoint> const&
|
|
|
|
, sha1_hash const&)> f)
|
|
|
|
{
|
|
|
|
m_dht.announce(ih, listen_port, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// translate bittorrent kademlia message into the generice kademlia message
|
|
|
|
// used by the library
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::on_receive(asio::error_code const& error, size_t bytes_transferred)
|
2006-08-01 17:27:08 +02:00
|
|
|
try
|
|
|
|
{
|
2006-08-01 18:59:12 +02:00
|
|
|
if (error == asio::error::operation_aborted) return;
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
int current_buffer = m_buffer;
|
|
|
|
m_buffer = (m_buffer + 1) & 1;
|
|
|
|
m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
|
|
|
|
, m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
|
2007-02-25 10:42:43 +01:00
|
|
|
, m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
|
2006-08-01 17:27:08 +02:00
|
|
|
|
2006-08-01 18:59:12 +02:00
|
|
|
if (error) return;
|
|
|
|
|
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
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
using libtorrent::entry;
|
|
|
|
using libtorrent::bdecode;
|
|
|
|
|
|
|
|
assert(bytes_transferred > 0);
|
|
|
|
|
|
|
|
entry e = bdecode(m_in_buf[current_buffer].begin()
|
|
|
|
, m_in_buf[current_buffer].end());
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-07 20:12:03 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << time_now_string() << " RECEIVED ["
|
|
|
|
<< m_remote_endpoint[current_buffer] << "]:";
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
libtorrent::dht::msg m;
|
|
|
|
m.message_id = 0;
|
|
|
|
m.addr = m_remote_endpoint[current_buffer];
|
|
|
|
m.transaction_id = e["t"].string();
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
try
|
|
|
|
{
|
|
|
|
entry const* ver = e.find_key("v");
|
|
|
|
if (!ver) throw std::exception();
|
|
|
|
|
|
|
|
std::string const& client = ver->string();
|
|
|
|
if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "UT"))
|
|
|
|
{
|
|
|
|
++m_ut_message_input;
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: uTorrent";
|
|
|
|
}
|
|
|
|
else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "LT"))
|
|
|
|
{
|
|
|
|
++m_lt_message_input;
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: libtorrent";
|
|
|
|
}
|
|
|
|
else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MP"))
|
|
|
|
{
|
|
|
|
++m_mp_message_input;
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: MooPolice";
|
|
|
|
}
|
|
|
|
else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "GR"))
|
|
|
|
{
|
|
|
|
++m_gr_message_input;
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: GetRight";
|
|
|
|
}
|
2007-03-02 19:40:02 +01:00
|
|
|
else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MO"))
|
|
|
|
{
|
|
|
|
++m_mo_message_input;
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: Mono Torrent";
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
else
|
|
|
|
{
|
2007-05-12 03:52:25 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << " client: " << client;
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
TORRENT_LOG(dht_tracker) << " client: generic";
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
std::string const& msg_type = e["y"].string();
|
|
|
|
|
|
|
|
if (msg_type == "r")
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " reply: transaction: "
|
|
|
|
<< m.transaction_id;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m.reply = true;
|
|
|
|
entry const& r = e["r"];
|
|
|
|
std::string const& id = r["id"].string();
|
|
|
|
if (id.size() != 20) throw std::runtime_error("invalid size of id");
|
|
|
|
std::copy(id.begin(), id.end(), m.id.begin());
|
|
|
|
|
2007-03-09 21:37:17 +01:00
|
|
|
if (entry const* n = r.find_key("values"))
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
m.peers.clear();
|
2007-03-09 21:37:17 +01:00
|
|
|
if (n->list().size() == 1)
|
|
|
|
{
|
|
|
|
// assume it's mainline format
|
|
|
|
std::string const& peers = n->list().front().string();
|
|
|
|
std::string::const_iterator i = peers.begin();
|
|
|
|
std::string::const_iterator end = peers.end();
|
|
|
|
|
|
|
|
while (std::distance(i, end) >= 6)
|
|
|
|
m.peers.push_back(read_v4_endpoint<tcp::endpoint>(i));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// assume it's uTorrent/libtorrent format
|
|
|
|
read_endpoint_list<tcp::endpoint>(n, m.peers);
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-09-21 20:22:26 +02:00
|
|
|
m.nodes.clear();
|
2006-08-01 17:27:08 +02:00
|
|
|
if (entry const* n = r.find_key("nodes"))
|
|
|
|
{
|
|
|
|
std::string const& nodes = n->string();
|
|
|
|
std::string::const_iterator i = nodes.begin();
|
|
|
|
std::string::const_iterator end = nodes.end();
|
|
|
|
|
|
|
|
while (std::distance(i, end) >= 26)
|
|
|
|
{
|
|
|
|
node_id id;
|
|
|
|
std::copy(i, i + 20, id.begin());
|
|
|
|
i += 20;
|
|
|
|
m.nodes.push_back(libtorrent::dht::node_entry(
|
2006-09-01 05:06:00 +02:00
|
|
|
id, read_v4_endpoint<udp::endpoint>(i)));
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-09-21 20:22:26 +02:00
|
|
|
if (entry const* n = r.find_key("nodes2"))
|
|
|
|
{
|
|
|
|
entry::list_type const& contacts = n->list();
|
|
|
|
for (entry::list_type::const_iterator i = contacts.begin()
|
|
|
|
, end(contacts.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
std::string const& p = i->string();
|
|
|
|
if (p.size() < 6 + 20) continue;
|
|
|
|
std::string::const_iterator in = p.begin();
|
|
|
|
|
|
|
|
node_id id;
|
|
|
|
std::copy(in, in + 20, id.begin());
|
|
|
|
in += 20;
|
|
|
|
if (p.size() == 6 + 20)
|
|
|
|
m.nodes.push_back(libtorrent::dht::node_entry(
|
|
|
|
id, read_v4_endpoint<udp::endpoint>(in)));
|
|
|
|
else if (p.size() == 18 + 20)
|
|
|
|
m.nodes.push_back(libtorrent::dht::node_entry(
|
|
|
|
id, read_v6_endpoint<udp::endpoint>(in)));
|
|
|
|
}
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " nodes2 + nodes: " << m.nodes.size();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
entry const* token = r.find_key("token");
|
|
|
|
if (token) m.write_token = *token;
|
|
|
|
}
|
|
|
|
else if (msg_type == "q")
|
|
|
|
{
|
|
|
|
m.reply = false;
|
|
|
|
entry const& a = e["a"];
|
|
|
|
std::string const& id = a["id"].string();
|
|
|
|
if (id.size() != 20) throw std::runtime_error("invalid size of id");
|
|
|
|
std::copy(id.begin(), id.end(), m.id.begin());
|
|
|
|
|
|
|
|
std::string request_kind(e["q"].string());
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " query: " << request_kind;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (request_kind == "ping")
|
|
|
|
{
|
|
|
|
m.message_id = libtorrent::dht::messages::ping;
|
|
|
|
}
|
|
|
|
else if (request_kind == "find_node")
|
|
|
|
{
|
|
|
|
std::string const& target = a["target"].string();
|
|
|
|
if (target.size() != 20) throw std::runtime_error("invalid size of target id");
|
|
|
|
std::copy(target.begin(), target.end(), m.info_hash.begin());
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " target: "
|
|
|
|
<< boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
m.message_id = libtorrent::dht::messages::find_node;
|
|
|
|
}
|
|
|
|
else if (request_kind == "get_peers")
|
|
|
|
{
|
|
|
|
std::string const& info_hash = a["info_hash"].string();
|
|
|
|
if (info_hash.size() != 20) throw std::runtime_error("invalid size of info-hash");
|
|
|
|
std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin());
|
|
|
|
m.message_id = libtorrent::dht::messages::get_peers;
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " info_hash: "
|
|
|
|
<< boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (request_kind == "announce_peer")
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
++m_announces;
|
|
|
|
#endif
|
|
|
|
std::string const& info_hash = a["info_hash"].string();
|
|
|
|
if (info_hash.size() != 20)
|
|
|
|
throw std::runtime_error("invalid size of info-hash");
|
|
|
|
std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin());
|
|
|
|
m.port = a["port"].integer();
|
|
|
|
m.write_token = a["token"];
|
|
|
|
m.message_id = libtorrent::dht::messages::announce_peer;
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " info_hash: "
|
|
|
|
<< boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
TORRENT_LOG(dht_tracker) << " port: " << m.port;
|
|
|
|
|
|
|
|
if (!m_dht.verify_token(m))
|
|
|
|
++m_failed_announces;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " *** UNSUPPORTED REQUEST *** : "
|
|
|
|
<< request_kind;
|
|
|
|
#endif
|
|
|
|
throw std::runtime_error("unsupported request: " + request_kind);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (msg_type == "e")
|
|
|
|
{
|
|
|
|
entry::list_type const& list = e["e"].list();
|
|
|
|
m.message_id = messages::error;
|
|
|
|
m.error_msg = list.back().string();
|
|
|
|
m.error_code = list.front().integer();
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-23 10:45:12 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << " incoming error: " << m.error_code << " "
|
2006-08-01 17:27:08 +02:00
|
|
|
<< m.error_msg;
|
|
|
|
#endif
|
2007-05-12 03:52:25 +02:00
|
|
|
throw std::runtime_error("DHT error message");
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " *** UNSUPPORTED MESSAGE TYPE *** : "
|
|
|
|
<< msg_type;
|
|
|
|
#endif
|
|
|
|
throw std::runtime_error("unsupported message type: " + msg_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
if (!m.reply)
|
|
|
|
{
|
|
|
|
++m_queries_received[m.message_id];
|
|
|
|
m_queries_bytes_received[m.message_id] += int(bytes_transferred);
|
|
|
|
}
|
|
|
|
TORRENT_LOG(dht_tracker) << e;
|
|
|
|
#endif
|
2007-05-12 03:52:25 +02:00
|
|
|
assert(m.message_id != messages::error);
|
2006-08-01 17:27:08 +02:00
|
|
|
m_dht.incoming(m);
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
2006-10-02 12:06:31 +02:00
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-08 02:55:43 +02:00
|
|
|
int current_buffer = (m_buffer + 1) & 1;
|
|
|
|
std::string msg(m_in_buf[current_buffer].begin()
|
2007-05-23 10:45:12 +02:00
|
|
|
, m_in_buf[current_buffer].begin() + bytes_transferred);
|
2006-10-02 12:06:31 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << "invalid incoming packet: "
|
2007-05-23 10:45:12 +02:00
|
|
|
<< e.what() << "\n" << msg << "\n";
|
2006-10-02 12:06:31 +02:00
|
|
|
#endif
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
entry dht_tracker::state() const
|
|
|
|
{
|
|
|
|
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);
|
2006-08-01 17:27:08 +02:00
|
|
|
write_endpoint(i->addr, 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);
|
2006-08-01 17:27:08 +02:00
|
|
|
write_endpoint(i->addr, 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret["node-id"] = boost::lexical_cast<std::string>(m_dht.nid());
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::add_node(udp::endpoint node)
|
|
|
|
{
|
|
|
|
m_dht.add_node(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void dht_tracker::add_node(std::pair<std::string, int> const& node)
|
|
|
|
{
|
|
|
|
udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
|
2006-12-15 18:47:21 +01:00
|
|
|
m_host_resolver.async_resolve(q, m_strand.wrap(
|
2007-02-25 10:42:43 +01:00
|
|
|
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
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::on_name_lookup(asio::error_code const& e
|
2006-09-27 19:20:18 +02:00
|
|
|
, udp::resolver::iterator host) try
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
if (e || host == udp::resolver::iterator()) return;
|
|
|
|
add_node(host->endpoint());
|
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
2006-09-27 19:20:18 +02:00
|
|
|
void dht_tracker::add_router_node(std::pair<std::string, int> const& node)
|
|
|
|
{
|
|
|
|
udp::resolver::query q(node.first, lexical_cast<std::string>(node.second));
|
2006-12-15 18:47:21 +01:00
|
|
|
m_host_resolver.async_resolve(q, m_strand.wrap(
|
2007-02-25 10:42:43 +01:00
|
|
|
bind(&dht_tracker::on_router_name_lookup, self(), _1, _2)));
|
2006-09-27 19:20:18 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void dht_tracker::on_router_name_lookup(asio::error_code const& e
|
2006-09-27 19:20:18 +02:00
|
|
|
, udp::resolver::iterator host) try
|
|
|
|
{
|
|
|
|
if (e || host == udp::resolver::iterator()) return;
|
|
|
|
m_dht.add_router_node(host->endpoint());
|
|
|
|
}
|
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
assert(false);
|
|
|
|
};
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
void dht_tracker::on_bootstrap()
|
|
|
|
{}
|
|
|
|
|
2007-05-07 20:00:17 +02:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
void write_nodes_entry(entry& r, libtorrent::dht::msg const& m)
|
|
|
|
{
|
|
|
|
bool ipv6_nodes = false;
|
|
|
|
r["nodes"] = entry(entry::string_t);
|
|
|
|
entry& n = r["nodes"];
|
|
|
|
std::back_insert_iterator<std::string> out(n.string());
|
|
|
|
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
|
|
|
, end(m.nodes.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (!i->addr.address().is_v4())
|
|
|
|
{
|
|
|
|
ipv6_nodes = true;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::copy(i->id.begin(), i->id.end(), out);
|
|
|
|
write_endpoint(i->addr, out);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipv6_nodes)
|
|
|
|
{
|
|
|
|
r["nodes2"] = entry(entry::list_t);
|
|
|
|
entry& p = r["nodes2"];
|
|
|
|
std::string endpoint;
|
|
|
|
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
|
|
|
, end(m.nodes.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (!i->addr.address().is_v6()) continue;
|
|
|
|
endpoint.resize(18 + 20);
|
|
|
|
std::string::iterator out = endpoint.begin();
|
|
|
|
std::copy(i->id.begin(), i->id.end(), out);
|
|
|
|
out += 20;
|
|
|
|
write_endpoint(i->addr, out);
|
|
|
|
endpoint.resize(out - endpoint.begin());
|
|
|
|
p.list().push_back(entry(endpoint));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
void dht_tracker::send_packet(msg const& m)
|
2007-05-12 03:52:25 +02:00
|
|
|
try
|
2006-08-01 17:27:08 +02:00
|
|
|
{
|
|
|
|
using libtorrent::bencode;
|
|
|
|
using libtorrent::entry;
|
|
|
|
entry e(entry::dictionary_t);
|
2007-05-23 10:45:12 +02:00
|
|
|
assert(!m.transaction_id.empty() || m.message_id == messages::error);
|
2006-08-01 17:27:08 +02:00
|
|
|
e["t"] = m.transaction_id;
|
2007-05-12 03:52:25 +02:00
|
|
|
static char const version_str[] = {'L', 'T'
|
|
|
|
, LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR};
|
|
|
|
e["v"] = std::string(version_str, version_str + 4);
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-07 20:12:03 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << time_now_string()
|
2006-08-01 17:27:08 +02:00
|
|
|
<< " SENDING [" << m.addr << "]:";
|
|
|
|
TORRENT_LOG(dht_tracker) << " transaction: " << m.transaction_id;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (m.message_id == messages::error)
|
|
|
|
{
|
|
|
|
assert(m.reply);
|
|
|
|
e["y"] = "e";
|
|
|
|
entry error_list(entry::list_t);
|
2007-05-12 03:52:25 +02:00
|
|
|
assert(m.error_code > 200 && m.error_code <= 204);
|
2006-08-01 17:27:08 +02:00
|
|
|
error_list.list().push_back(entry(m.error_code));
|
|
|
|
error_list.list().push_back(entry(m.error_msg));
|
|
|
|
e["e"] = error_list;
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-12 03:52:25 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << time_now_string()
|
2007-05-23 10:45:12 +02:00
|
|
|
<< " outgoing error: " << m.error_code << " " << m.error_msg;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else if (m.reply)
|
|
|
|
{
|
|
|
|
e["y"] = "r";
|
|
|
|
e["r"] = entry(entry::dictionary_t);
|
|
|
|
entry& r = e["r"];
|
|
|
|
r["id"] = std::string(m.id.begin(), m.id.end());
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2007-05-07 20:12:03 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << time_now_string()
|
|
|
|
<< " reply: " << messages::ids[m.message_id];
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (m.write_token.type() != entry::undefined_t)
|
|
|
|
r["token"] = m.write_token;
|
|
|
|
|
|
|
|
switch (m.message_id)
|
|
|
|
{
|
|
|
|
case messages::ping:
|
|
|
|
break;
|
|
|
|
case messages::find_node:
|
|
|
|
{
|
2007-05-07 20:00:17 +02:00
|
|
|
write_nodes_entry(r, m);
|
2006-08-01 17:27:08 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case messages::get_peers:
|
|
|
|
{
|
|
|
|
if (m.peers.empty())
|
|
|
|
{
|
2007-05-07 20:00:17 +02:00
|
|
|
write_nodes_entry(r, m);
|
2006-08-01 17:27:08 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
r["values"] = entry(entry::list_t);
|
|
|
|
entry& p = r["values"];
|
|
|
|
std::string endpoint;
|
|
|
|
for (msg::peers_t::const_iterator i = m.peers.begin()
|
|
|
|
, end(m.peers.end()); i != end; ++i)
|
|
|
|
{
|
2007-05-07 20:00:17 +02:00
|
|
|
endpoint.resize(18);
|
2006-08-01 17:27:08 +02:00
|
|
|
std::string::iterator out = endpoint.begin();
|
|
|
|
write_endpoint(*i, out);
|
2007-05-07 20:00:17 +02:00
|
|
|
endpoint.resize(out - endpoint.begin());
|
2006-08-01 17:27:08 +02:00
|
|
|
p.list().push_back(entry(endpoint));
|
|
|
|
}
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case messages::announce_peer:
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
e["y"] = "q";
|
|
|
|
e["a"] = entry(entry::dictionary_t);
|
|
|
|
entry& a = e["a"];
|
|
|
|
a["id"] = std::string(m.id.begin(), m.id.end());
|
|
|
|
|
|
|
|
if (m.write_token.type() != entry::undefined_t)
|
|
|
|
a["token"] = m.write_token;
|
|
|
|
assert(m.message_id <= messages::error);
|
|
|
|
e["q"] = messages::ids[m.message_id];
|
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " query: "
|
|
|
|
<< messages::ids[m.message_id];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
switch (m.message_id)
|
|
|
|
{
|
|
|
|
case messages::find_node:
|
|
|
|
{
|
|
|
|
a["target"] = std::string(m.info_hash.begin(), m.info_hash.end());
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " target: "
|
|
|
|
<< boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case messages::get_peers:
|
|
|
|
{
|
|
|
|
a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " info_hash: "
|
|
|
|
<< boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case messages::announce_peer:
|
|
|
|
a["port"] = m_settings.service_port;
|
2006-12-14 01:54:37 +01:00
|
|
|
a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
|
2006-08-01 17:27:08 +02:00
|
|
|
a["token"] = m.write_token;
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
|
|
TORRENT_LOG(dht_tracker) << " port: "
|
|
|
|
<< m_settings.service_port
|
|
|
|
<< " info_hash: " << boost::lexical_cast<std::string>(m.info_hash);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
m_send_buf.clear();
|
|
|
|
bencode(std::back_inserter(m_send_buf), e);
|
2007-05-12 03:52:25 +02:00
|
|
|
asio::error_code ec;
|
2006-08-01 17:27:08 +02:00
|
|
|
m_socket.send_to(asio::buffer(&m_send_buf[0]
|
2007-05-12 03:52:25 +02:00
|
|
|
, (int)m_send_buf.size()), m.addr, 0, ec);
|
|
|
|
if (ec) return;
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
2006-08-06 18:36:00 +02:00
|
|
|
m_total_out_bytes += m_send_buf.size();
|
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
if (m.reply)
|
|
|
|
{
|
|
|
|
++m_replies_sent[m.message_id];
|
|
|
|
m_replies_bytes_sent[m.message_id] += int(m_send_buf.size());
|
|
|
|
}
|
2006-08-06 18:36:00 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_queries_out_bytes += m_send_buf.size();
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
TORRENT_LOG(dht_tracker) << e;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!m.piggy_backed_ping) return;
|
|
|
|
|
|
|
|
msg pm;
|
|
|
|
pm.reply = false;
|
|
|
|
pm.piggy_backed_ping = false;
|
|
|
|
pm.message_id = messages::ping;
|
|
|
|
pm.transaction_id = m.ping_transaction_id;
|
|
|
|
pm.id = m.id;
|
|
|
|
pm.addr = m.addr;
|
|
|
|
|
|
|
|
send_packet(pm);
|
|
|
|
}
|
2007-05-12 03:52:25 +02:00
|
|
|
catch (std::exception&)
|
|
|
|
{
|
|
|
|
// m_send may fail with "no route to host"
|
|
|
|
// but it shouldn't throw since an error code
|
|
|
|
// is passed in instead
|
|
|
|
assert(false);
|
|
|
|
}
|
2006-08-01 17:27:08 +02:00
|
|
|
|
|
|
|
}}
|
|
|
|
|