limit number of torrents tracked by DHT and support DHT name lookups

This commit is contained in:
Arvid Norberg 2010-11-27 03:09:28 +00:00
parent fa80c95d62
commit f21251cba8
7 changed files with 125 additions and 4 deletions

View File

@ -1,3 +1,4 @@
* support DHT name lookup
* optimized memory usage of torrent_info and file_storage, forcing some API changes * optimized memory usage of torrent_info and file_storage, forcing some API changes
around file_storage and file_entry around file_storage and file_entry
* support trackerid tracker extension * support trackerid tracker extension
@ -57,6 +58,7 @@
incoming connection incoming connection
* added more detailed instrumentation of the disk I/O thread * added more detailed instrumentation of the disk I/O thread
* limit number of torrents tracked by DHT
* fixed bug when allow_multiple_connections_per_ip was enabled * fixed bug when allow_multiple_connections_per_ip was enabled
* potential WOW64 fix for unbuffered I/O (windows) * potential WOW64 fix for unbuffered I/O (windows)
* expose set_alert_queue_size_limit to python binding * expose set_alert_queue_size_limit to python binding

View File

@ -3908,6 +3908,7 @@ session_settings
bool low_prio_disk; bool low_prio_disk;
int local_service_announce_interval; int local_service_announce_interval;
int dht_announce_interval; int dht_announce_interval;
int dht_max_torrents;
int udp_tracker_token_expiry; int udp_tracker_token_expiry;
bool volatile_read_cache; bool volatile_read_cache;
@ -4512,6 +4513,9 @@ This interval is specified in seconds.
torrents to the distributed hash table (DHT). This is specified to torrents to the distributed hash table (DHT). This is specified to
be 15 minutes which is its default. be 15 minutes which is its default.
``dht_max_torrents`` is the max number of torrents we will track
in the DHT.
``udp_tracker_token_expiry`` is the number of seconds libtorrent ``udp_tracker_token_expiry`` is the number of seconds libtorrent
will keep UDP tracker connection tokens around for. This is specified will keep UDP tracker connection tokens around for. This is specified
to be 60 seconds, and defaults to that. The higher this value is, the to be 60 seconds, and defaults to that. The higher this value is, the

View File

@ -95,6 +95,7 @@ struct peer_entry
// this is a group. It contains a set of group members // this is a group. It contains a set of group members
struct torrent_entry struct torrent_entry
{ {
std::string name;
std::set<peer_entry> peers; std::set<peer_entry> peers;
}; };

View File

@ -206,6 +206,7 @@ namespace libtorrent
, low_prio_disk(true) , low_prio_disk(true)
, local_service_announce_interval(5 * 60) , local_service_announce_interval(5 * 60)
, dht_announce_interval(15 * 60) , dht_announce_interval(15 * 60)
, dht_max_torrents(3000)
, udp_tracker_token_expiry(60) , udp_tracker_token_expiry(60)
, volatile_read_cache(false) , volatile_read_cache(false)
, guided_read_cache(true) , guided_read_cache(true)
@ -780,6 +781,9 @@ namespace libtorrent
// torrents. Defaults to 15 minutes // torrents. Defaults to 15 minutes
int dht_announce_interval; int dht_announce_interval;
// this is the max number of torrents the DHT will track
int dht_max_torrents;
// the number of seconds a connection ID received // the number of seconds a connection ID received
// from a UDP tracker is valid for. This is specified // from a UDP tracker is valid for. This is specified
// as 60 seconds // as 60 seconds

View File

@ -511,7 +511,7 @@ namespace libtorrent { namespace dht
lazy_entry e; lazy_entry e;
int pos; int pos;
error_code ec; error_code ec;
int ret = lazy_bdecode(buf, buf + bytes_transferred, e, ec, &pos); int ret = lazy_bdecode(buf, buf + bytes_transferred, e, ec, &pos, 10, 500);
if (ret != 0) if (ret != 0)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING

View File

@ -536,6 +536,8 @@ bool node_impl::lookup_peers(sha1_hash const& info_hash, entry& reply) const
torrent_entry const& v = i->second; torrent_entry const& v = i->second;
if (v.peers.empty()) return false; if (v.peers.empty()) return false;
if (!v.name.empty()) reply["n"] = v.name;
int num = (std::min)((int)v.peers.size(), m_settings.max_peers_reply); int num = (std::min)((int)v.peers.size(), m_settings.max_peers_reply);
int t = 0; int t = 0;
int m = 0; int m = 0;
@ -753,10 +755,11 @@ void node_impl::incoming_request(msg const& m, entry& e)
{"info_hash", lazy_entry::string_t, 20, 0}, {"info_hash", lazy_entry::string_t, 20, 0},
{"port", lazy_entry::int_t, 0, 0}, {"port", lazy_entry::int_t, 0, 0},
{"token", lazy_entry::string_t, 0, 0}, {"token", lazy_entry::string_t, 0, 0},
{"n", lazy_entry::string_t, 0, key_desc_t::optional},
}; };
lazy_entry const* msg_keys[3]; lazy_entry const* msg_keys[4];
if (!verify_message(arg_ent, msg_desc, msg_keys, 3, error_string, sizeof(error_string))) if (!verify_message(arg_ent, msg_desc, msg_keys, 4, error_string, sizeof(error_string)))
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
++g_failed_announces; ++g_failed_announces;
@ -795,7 +798,33 @@ void node_impl::incoming_request(msg const& m, entry& e)
// the table get a chance to add it. // the table get a chance to add it.
m_table.node_seen(id, m.addr); m_table.node_seen(id, m.addr);
if (!m_map.empty() && m_map.size() >= m_ses.settings().dht_max_torrents)
{
// we need to remove some. Remove the ones with the
// fewest peers
int num_peers = m_map.begin()->second.peers.size();
table_t::iterator candidate = m_map.begin();
for (table_t::iterator i = m_map.begin()
, end(m_map.end()); i != end; ++i)
{
if (i->second.peers.size() > num_peers) continue;
if (i->first == info_hash) continue;
num_peers = i->second.peers.size();
candidate = i;
}
m_map.erase(candidate);
}
torrent_entry& v = m_map[info_hash]; torrent_entry& v = m_map[info_hash];
// the peer announces a torrent name, and we don't have a name
// for this torrent. Store it.
if (msg_keys[3] && v.name.empty())
{
std::string name = msg_keys[3]->string_value();
if (name.size() > 50) name.resize(50);
v.name = name;
}
peer_entry e; peer_entry e;
e.addr = tcp::endpoint(m.addr.address(), port); e.addr = tcp::endpoint(m.addr.address(), port);
e.added = time_now(); e.added = time_now();

View File

@ -43,7 +43,9 @@ using namespace libtorrent;
int dht_port = 48199; int dht_port = 48199;
void send_dht_msg(datagram_socket& sock, char const* msg, lazy_entry* reply, char const* t = "10") void send_dht_msg(datagram_socket& sock, char const* msg, lazy_entry* reply
, char const* t = "10", char const* info_hash = 0, char const* name = 0
, char const* token = 0, int port = 0)
{ {
entry e; entry e;
e["q"] = msg; e["q"] = msg;
@ -51,6 +53,10 @@ void send_dht_msg(datagram_socket& sock, char const* msg, lazy_entry* reply, cha
e["y"] = "q"; e["y"] = "q";
entry::dictionary_type& a = e["a"].dict(); entry::dictionary_type& a = e["a"].dict();
a["id"] = "00000000000000000000"; a["id"] = "00000000000000000000";
if (info_hash) a["info_hash"] = info_hash;
if (name) a["n"] = name;
if (token) a["token"] = token;
if (port) a["port"] = port;
char msg_buf[1500]; char msg_buf[1500];
int size = bencode(msg_buf, e); int size = bencode(msg_buf, e);
@ -98,6 +104,7 @@ int test_main()
{"t", lazy_entry::string_t, 2, 0}, {"t", lazy_entry::string_t, 2, 0},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, pong_desc, parsed, 2, error_string, sizeof(error_string)); ret = dht::verify_message(&response, pong_desc, parsed, 2, error_string, sizeof(error_string));
TEST_CHECK(ret); TEST_CHECK(ret);
if (ret) if (ret)
@ -105,6 +112,10 @@ int test_main()
TEST_CHECK(parsed[0]->string_value() == "r"); TEST_CHECK(parsed[0]->string_value() == "r");
TEST_CHECK(parsed[1]->string_value() == "10"); TEST_CHECK(parsed[1]->string_value() == "10");
} }
else
{
fprintf(stderr, "invalid ping response: %s\n", error_string);
}
// ====== invalid message ====== // ====== invalid message ======
@ -115,6 +126,7 @@ int test_main()
{"e", lazy_entry::list_t, 0, 0}, {"e", lazy_entry::list_t, 0, 0},
}; };
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, err_desc, parsed, 2, error_string, sizeof(error_string)); ret = dht::verify_message(&response, err_desc, parsed, 2, error_string, sizeof(error_string));
TEST_CHECK(ret); TEST_CHECK(ret);
if (ret) if (ret)
@ -132,6 +144,75 @@ int test_main()
TEST_ERROR("invalid error response"); TEST_ERROR("invalid error response");
} }
} }
else
{
fprintf(stderr, "invalid error response: %s\n", error_string);
}
// ====== get_peers ======
send_dht_msg(sock, "get_peers", &response, "10", "01010101010101010101");
dht::key_desc_t peer1_desc[] = {
{"y", lazy_entry::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, 0},
};
std::string token;
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, peer1_desc, parsed, 2, error_string, sizeof(error_string));
TEST_CHECK(ret);
if (ret)
{
TEST_CHECK(parsed[0]->string_value() == "r");
token = parsed[1]->dict_find_string_value("token");
}
else
{
fprintf(stderr, "invalid get_peers response: %s\n", error_string);
}
// ====== announce ======
send_dht_msg(sock, "announce_peer", &response, "10", "01010101010101010101", "test", token.c_str(), 8080);
dht::key_desc_t ann_desc[] = {
{"y", lazy_entry::string_t, 1, 0},
};
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, ann_desc, parsed, 1, error_string, sizeof(error_string));
TEST_CHECK(ret);
if (ret)
{
TEST_CHECK(parsed[0]->string_value() == "r");
}
else
{
fprintf(stderr, "invalid announce response: %s\n", error_string);
}
// ====== get_peers ======
send_dht_msg(sock, "get_peers", &response, "10", "01010101010101010101");
dht::key_desc_t peer2_desc[] = {
{"y", lazy_entry::string_t, 1, 0},
{"r", lazy_entry::dict_t, 0, 0},
};
fprintf(stderr, "msg: %s\n", print_entry(response).c_str());
ret = dht::verify_message(&response, peer2_desc, parsed, 2, error_string, sizeof(error_string));
TEST_CHECK(ret);
if (ret)
{
TEST_CHECK(parsed[0]->string_value() == "r");
TEST_EQUAL(parsed[1]->dict_find_string_value("n"), "test");
}
else
{
fprintf(stderr, "invalid get_peers response: %s\n", error_string);
}
return 0; return 0;
} }