diff --git a/include/libtorrent/aux_/time.hpp b/include/libtorrent/aux_/time.hpp index 12c278f99..a9afb894b 100644 --- a/include/libtorrent/aux_/time.hpp +++ b/include/libtorrent/aux_/time.hpp @@ -44,7 +44,7 @@ namespace libtorrent { namespace aux // resolution of this timer is about 100 ms. time_point const& time_now(); - void update_time_now(); + TORRENT_EXTRA_EXPORT void update_time_now(); } } diff --git a/simulation/Jamfile b/simulation/Jamfile index f834eb7e1..c6176a18f 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -28,6 +28,7 @@ alias libtorrent-sims : [ run test_super_seeding.cpp ] [ run test_utp.cpp ] [ run test_dht.cpp ] + [ run test_dht_storage.cpp ] [ run test_pe_crypto.cpp ] [ run test_metadata_extension.cpp ] [ run test_trackers_extension.cpp ] diff --git a/simulation/test_dht_storage.cpp b/simulation/test_dht_storage.cpp new file mode 100644 index 000000000..f669c6b75 --- /dev/null +++ b/simulation/test_dht_storage.cpp @@ -0,0 +1,157 @@ +/* + +Copyright (c) 2015, Alden Torres +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 "test.hpp" +#include "settings.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/kademlia/node.hpp" // for verify_message + +#include "libtorrent/kademlia/dht_storage.hpp" +#include "libtorrent/kademlia/item.hpp" + +#include "libtorrent/io_service.hpp" +#include "libtorrent/address.hpp" +#include "libtorrent/aux_/time.hpp" + +#include "simulator/simulator.hpp" +#include + +using namespace libtorrent; +using namespace libtorrent::dht; +using namespace sim; +using namespace sim::chrono; +using namespace sim::asio; +using sim::simulation; +using sim::default_config; + +namespace +{ + dht_settings test_settings() { + dht_settings sett; + sett.max_torrents = 2; + sett.max_dht_items = 2; + sett.item_lifetime = seconds(120 * 60).count(); + return sett; + } + + static sha1_hash to_hash(char const *s) { + sha1_hash ret; + from_hex(s, 40, (char *) &ret[0]); + return ret; + } +} + +void timer_tick(boost::shared_ptr s + , dht_storage_counters const& c + , boost::system::error_code const& ec) +{ + libtorrent::aux::update_time_now(); + s->tick(); + + TEST_EQUAL(s->counters().peers, c.peers); + TEST_EQUAL(s->counters().torrents, c.torrents); + TEST_EQUAL(s->counters().immutable_data, c.immutable_data); + TEST_EQUAL(s->counters().mutable_data, c.mutable_data); +} + +void test_expiration(high_resolution_clock::duration const& expiry_time + , boost::shared_ptr s + , dht_storage_counters const& c) +{ + default_config cfg; + simulation sim(cfg); + sim::asio::io_service ios(sim, asio::ip::address_v4::from_string("10.0.0.1")); + + sim::asio::high_resolution_timer timer(ios); + timer.expires_from_now(expiry_time); + timer.async_wait(boost::bind(&timer_tick, s, c, _1)); + + boost::system::error_code ec; + sim.run(ec); +} + +TORRENT_TEST(dht_storage_counters) +{ + dht_settings sett = test_settings(); + boost::shared_ptr s(dht_default_storage_constructor(node_id(0), sett)); + + TEST_CHECK(s.get() != NULL); + + sha1_hash n1 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee401"); + sha1_hash n2 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee402"); + sha1_hash n3 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee403"); + sha1_hash n4 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee404"); + + tcp::endpoint p1 = tcp::endpoint(address::from_string("124.31.75.21"), 1); + tcp::endpoint p2 = tcp::endpoint(address::from_string("124.31.75.22"), 1); + tcp::endpoint p3 = tcp::endpoint(address::from_string("124.31.75.23"), 1); + tcp::endpoint p4 = tcp::endpoint(address::from_string("124.31.75.24"), 1); + + s->announce_peer(n1, p1, "torrent_name", false); + + s->announce_peer(n2, p2, "torrent_name1", false); + s->announce_peer(n2, p3, "torrent_name1", false); + s->announce_peer(n3, p4, "torrent_name2", false); + + entry item; + + s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21")); + + s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); + + char public_key[item_pk_len]; + char signature[item_sig_len]; + s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); + + dht_storage_counters c; + // note that we are using the aux global timer + + c.peers = 3; + c.torrents = 2; + c.immutable_data = 2; + c.mutable_data = 1; + test_expiration(minutes(30), s, c); // test expiration of torrents and peers + + c.peers = 0; + c.torrents = 0; + c.immutable_data = 2; + c.mutable_data = 1; + test_expiration(minutes(80), s, c); // test expiration of items before 2 hours + + c.peers = 0; + c.torrents = 0; + c.immutable_data = 0; + c.mutable_data = 0; + test_expiration(hours(1), s, c); // test expiration of everything after 3 hours +} diff --git a/src/kademlia/dht_storage.cpp b/src/kademlia/dht_storage.cpp index 149bbfc49..de8f2c414 100644 --- a/src/kademlia/dht_storage.cpp +++ b/src/kademlia/dht_storage.cpp @@ -106,19 +106,6 @@ namespace // TODO: 2 make this configurable in dht_settings enum { announce_interval = 30 }; - void purge_peers(std::set& peers) - { - for (std::set::iterator i = peers.begin() - , end(peers.end()); i != end;) - { - // the peer has timed out - if (i->added + minutes(int(announce_interval * 1.5f)) < aux::time_now()) - peers.erase(i++); - else - ++i; - } - } - struct dht_immutable_item { dht_immutable_item() : value(0), num_announcers(0), size(0) {} @@ -296,6 +283,7 @@ namespace candidate = i; } m_map.erase(candidate); + m_counters.peers -= num_peers; m_counters.torrents -= 1; } m_counters.torrents += 1; @@ -320,8 +308,13 @@ namespace peer.added = aux::time_now(); peer.seed = seed; std::set::iterator i = v->peers.find(peer); - if (i != v->peers.end()) v->peers.erase(i++); + if (i != v->peers.end()) + { + v->peers.erase(i++); + m_counters.peers -= 1; + } v->peers.insert(i, peer); + m_counters.peers += 1; } bool get_immutable_item(sha1_hash const& target @@ -489,7 +482,7 @@ namespace if (it != m_map.end()) { m_map.erase(it); - m_counters.torrents -= 1; + m_counters.torrents -= 1;// peers is decreased by purge_peers } } @@ -540,6 +533,22 @@ namespace table_t m_map; dht_immutable_table_t m_immutable_table; dht_mutable_table_t m_mutable_table; + + void purge_peers(std::set& peers) + { + for (std::set::iterator i = peers.begin() + , end(peers.end()); i != end;) + { + // the peer has timed out + if (i->added + minutes(int(announce_interval * 1.5f)) < aux::time_now()) + { + peers.erase(i++); + m_counters.peers -= 1; + } + else + ++i; + } + } }; } diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index a0bd34207..78db61d14 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -906,3 +906,8 @@ void stop_web_server() web_server_pid = 0; } +tcp::endpoint ep(char const* ip, int port) +{ + error_code ec; + return tcp::endpoint(address::from_string(ip, ec), port); +} diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 7bb850663..b350633e8 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -104,5 +104,7 @@ EXPORT int start_proxy(int type); EXPORT void stop_proxy(int port); EXPORT void stop_all_proxies(); +EXPORT libtorrent::tcp::endpoint ep(char const* ip, int port); + #endif diff --git a/test/test_dht_storage.cpp b/test/test_dht_storage.cpp index 4e5b4cba4..2e8ea4ff9 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "test.hpp" +#include "setup_transfer.hpp" using namespace libtorrent; using namespace libtorrent::dht; @@ -61,6 +62,7 @@ namespace dht_settings sett; sett.max_torrents = 2; sett.max_dht_items = 2; + sett.item_lifetime = seconds(120 * 60).count(); return sett; } @@ -74,9 +76,9 @@ namespace TORRENT_TEST(dht_storage) { dht_settings sett = test_settings(); - dht_storage_interface* s = dht_default_storage_constructor(node_id(0), sett); + boost::scoped_ptr s(dht_default_storage_constructor(node_id(0), sett)); - TEST_CHECK(s != NULL); + TEST_CHECK(s.get() != NULL); sha1_hash n1 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee401"); sha1_hash n2 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee402"); @@ -89,10 +91,10 @@ TORRENT_TEST(dht_storage) TEST_CHECK(peers["n"].string().empty()) TEST_CHECK(peers["values"].list().empty()); - tcp::endpoint p1 = tcp::endpoint(address::from_string("124.31.75.21"), 1); - tcp::endpoint p2 = tcp::endpoint(address::from_string("124.31.75.22"), 1); - tcp::endpoint p3 = tcp::endpoint(address::from_string("124.31.75.23"), 1); - tcp::endpoint p4 = tcp::endpoint(address::from_string("124.31.75.24"), 1); + tcp::endpoint p1 = ep("124.31.75.21", 1); + tcp::endpoint p2 = ep("124.31.75.22", 1); + tcp::endpoint p3 = ep("124.31.75.23", 1); + tcp::endpoint p4 = ep("124.31.75.24", 1); s->announce_peer(n1, p1, "torrent_name", false); s->get_peers(n1, false, false, peers); @@ -127,8 +129,52 @@ TORRENT_TEST(dht_storage) s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); r = s->get_mutable_item(n4, 0, false, item); TEST_CHECK(r); - - delete s; } -#endif \ No newline at end of file +TORRENT_TEST(dht_storage_counters) +{ + dht_settings sett = test_settings(); + boost::scoped_ptr s(dht_default_storage_constructor(node_id(0), sett)); + + TEST_CHECK(s.get() != NULL); + + sha1_hash n1 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee401"); + sha1_hash n2 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee402"); + sha1_hash n3 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee403"); + sha1_hash n4 = to_hash("5fbfbff10c5d6a4ec8a88e4c6ab4c28b95eee404"); + + TEST_EQUAL(s->counters().peers, 0); + TEST_EQUAL(s->counters().torrents, 0); + + tcp::endpoint p1 = ep("124.31.75.21", 1); + tcp::endpoint p2 = ep("124.31.75.22", 1); + tcp::endpoint p3 = ep("124.31.75.23", 1); + tcp::endpoint p4 = ep("124.31.75.24", 1); + + s->announce_peer(n1, p1, "torrent_name", false); + TEST_EQUAL(s->counters().peers, 1); + TEST_EQUAL(s->counters().torrents, 1); + + s->announce_peer(n2, p2, "torrent_name1", false); + s->announce_peer(n2, p3, "torrent_name1", false); + s->announce_peer(n3, p4, "torrent_name2", false); + TEST_EQUAL(s->counters().peers, 3); + TEST_EQUAL(s->counters().torrents, 2); + + entry item; + + s->put_immutable_item(n4, "123", 3, address::from_string("124.31.75.21")); + TEST_EQUAL(s->counters().immutable_data, 1); + + s->put_immutable_item(n1, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n2, "123", 3, address::from_string("124.31.75.21")); + s->put_immutable_item(n3, "123", 3, address::from_string("124.31.75.21")); + TEST_EQUAL(s->counters().immutable_data, 2); + + char public_key[item_pk_len]; + char signature[item_sig_len]; + s->put_mutable_item(n4, "123", 3, signature, 1, public_key, "salt", 4, address::from_string("124.31.75.21")); + TEST_EQUAL(s->counters().mutable_data, 1); +} + +#endif diff --git a/test/test_peer_list.cpp b/test/test_peer_list.cpp index 866f359b3..9bc4f0db6 100644 --- a/test/test_peer_list.cpp +++ b/test/test_peer_list.cpp @@ -48,11 +48,6 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; -static tcp::endpoint ep(char const* ip, int port) -{ - return tcp::endpoint(address_v4::from_string(ip), port); -} - struct mock_torrent; struct mock_peer_connection : peer_connection_interface diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index 4b0791432..7a1f91c0f 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -61,12 +61,6 @@ address_v6 v6(char const* str) } #endif -static tcp::endpoint ep(char const* ip, int port) -{ - error_code ec; - return tcp::endpoint(address::from_string(ip, ec), port); -} - TORRENT_TEST(primitives) { using namespace libtorrent;