From 6447a074ebffa325873386ed2d18db89fd635591 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 8 Jun 2007 23:02:31 +0000 Subject: [PATCH] fixes to allow-multiple-connections-per-ip and a unit test that run a swarm of 3 local peers --- include/libtorrent/session.hpp | 1 + src/bt_peer_connection.cpp | 5 +- src/policy.cpp | 34 ++++++-- src/session.cpp | 5 ++ test/Jamfile | 1 + test/setup_transfer.cpp | 60 ++++++++++---- test/setup_transfer.hpp | 7 +- test/test_metadata_extension.cpp | 3 +- test/test_pe_crypto.cpp | 3 +- test/test_swarm.cpp | 129 +++++++++++++++++++++++++++++++ 10 files changed, 220 insertions(+), 28 deletions(-) create mode 100644 test/test_swarm.cpp diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index c80ada5c9..f70dea73c 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -191,6 +191,7 @@ namespace libtorrent void set_port_filter(port_filter const& f); void set_peer_id(peer_id const& pid); void set_key(int key); + peer_id id() const; bool is_listening() const; diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index a95c6bed7..904d0dc26 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1373,10 +1373,11 @@ namespace libtorrent return p.connection != m_pc && p.connection && p.connection->pid() == m_id - && !p.connection->pid().is_all_zeros(); + && !p.connection->pid().is_all_zeros() + && p.ip.address() == m_pc->remote().address(); } - peer_id m_id; + peer_id const& m_id; peer_connection const* m_pc; }; } diff --git a/src/policy.cpp b/src/policy.cpp index 848e24710..fe119abc9 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -142,7 +142,19 @@ namespace bool operator()(policy::peer const& p) const { return p.ip.address() == m_ip.address(); } - tcp::endpoint m_ip; + tcp::endpoint const& m_ip; + }; + + struct match_peer_id + { + match_peer_id(peer_id const& id_) + : m_id(id_) + {} + + bool operator()(policy::peer const& p) const + { return p.connection && p.connection->pid() == m_id; } + + peer_id const& m_id; }; struct match_peer_connection @@ -152,9 +164,13 @@ namespace {} bool operator()(policy::peer const& p) const - { return p.connection == &m_conn; } + { + return p.connection == &m_conn + || (p.ip == m_conn.remote() + && p.type == policy::peer::connectable); + } - const peer_connection& m_conn; + peer_connection const& m_conn; }; @@ -923,7 +939,10 @@ namespace libtorrent if (m_torrent->settings().allow_multiple_connections_per_ip) { - i = m_peers.end(); + i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_connection(c)); } else { @@ -1008,7 +1027,10 @@ namespace libtorrent if (m_torrent->settings().allow_multiple_connections_per_ip) { - i = m_peers.end(); + i = std::find_if( + m_peers.begin() + , m_peers.end() + , match_peer_id(pid)); } else { @@ -1199,6 +1221,7 @@ namespace libtorrent c.add_free_upload(-diff); } } +/* if (!c.is_choked()) { c.send_choke(); @@ -1207,6 +1230,7 @@ namespace libtorrent if (m_torrent->is_seed()) seed_unchoke_one_peer(); else unchoke_one_peer(); } +*/ } bool policy::unchoke_one_peer() diff --git a/src/session.cpp b/src/session.cpp index 55c27cb05..40959f3ad 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -152,6 +152,11 @@ namespace libtorrent { m_impl->set_peer_id(id); } + + peer_id session::id() const + { + return m_impl->get_peer_id(); + } void session::set_key(int key) { diff --git a/test/Jamfile b/test/Jamfile index baf63129c..a0d7f5028 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -21,6 +21,7 @@ test-suite libtorrent : [ run test_ip_filter.cpp ] [ run test_hasher.cpp ] [ run test_metadata_extension.cpp ] + [ run test_swarm.cpp ] [ run test_allocate_resources.cpp ] [ run test_web_seed.cpp ] ; diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index fee22d21e..abc56de4d 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -21,57 +21,85 @@ void sleep(int msec) using namespace libtorrent; -boost::tuple setup_transfer( - session& ses1, session& ses2, bool clear_files, bool use_metadata_transfer) +boost::tuple +setup_transfer(session* ses1, session* ses2, session* ses3 + , bool clear_files, bool use_metadata_transfer) { using namespace boost::filesystem; + assert(ses1); + assert(ses2); + + assert(ses1->id() != ses2->id()); + if (ses3) + assert(ses3->id() != ses2->id()); + char const* tracker_url = "http://non-existent-name.com/announce"; torrent_info t; - t.add_file(path("temporary"), 42); - t.set_piece_size(256 * 1024); + int total_size = 2 * 1024 * 1024; + t.add_file(path("temporary"), total_size); + t.set_piece_size(16 * 1024); t.add_tracker(tracker_url); - std::vector piece(42); + std::vector piece(16 * 1024); std::fill(piece.begin(), piece.end(), 0xfe); // calculate the hash for all pieces int num = t.num_pieces(); + sha1_hash ph = hasher(&piece[0], piece.size()).final(); for (int i = 0; i < num; ++i) - { - t.set_hash(i, hasher(&piece[0], piece.size()).final()); - } + t.set_hash(i, ph); create_directory("./tmp1"); std::ofstream file("./tmp1/temporary"); - file.write(&piece[0], piece.size()); + while (total_size > 0) + { + file.write(&piece[0], std::min(int(piece.size()), total_size)); + total_size -= piece.size(); + } file.close(); if (clear_files) remove_all("./tmp2/temporary"); t.create_torrent(); - ses1.set_severity_level(alert::debug); - ses2.set_severity_level(alert::debug); + ses1->set_severity_level(alert::debug); + ses2->set_severity_level(alert::debug); // they should not use the same save dir, because the // file pool will complain if two torrents are trying to // use the same files - torrent_handle tor1 = ses1.add_torrent(t, "./tmp1"); + torrent_handle tor1 = ses1->add_torrent(t, "./tmp1"); torrent_handle tor2; + torrent_handle tor3; + if (ses3) tor3 = ses3->add_torrent(t, "./tmp3"); + if (use_metadata_transfer) - tor2 = ses2.add_torrent(tracker_url + tor2 = ses2->add_torrent(tracker_url , t.info_hash(), 0, "./tmp2"); else - tor2 = ses2.add_torrent(t, "./tmp2"); + tor2 = ses2->add_torrent(t, "./tmp2"); sleep(100); std::cerr << "connecting peer\n"; tor1.connect_peer(tcp::endpoint(address::from_string("127.0.0.1") - , ses2.listen_port())); + , ses2->listen_port())); - return boost::make_tuple(tor1, tor2); + if (ses3) + { + // give the other peers some time to get an initial + // set of pieces before they start sharing with each-other + sleep(10000); + tor3.connect_peer(tcp::endpoint( + address::from_string("127.0.0.1") + , ses2->listen_port())); + tor3.connect_peer(tcp::endpoint( + address::from_string("127.0.0.1") + , ses1->listen_port())); + } + + return boost::make_tuple(tor1, tor2, tor3); } diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 1d85c672d..5221a09cc 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -6,9 +6,10 @@ void sleep(int msec); -boost::tuple - setup_transfer(libtorrent::session& ses1, libtorrent::session& ses2 - , bool clear_files, bool use_metadata_transfer = true); +boost::tuple +setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2 + , libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true); #endif diff --git a/test/test_metadata_extension.cpp b/test/test_metadata_extension.cpp index 18b0adc92..dcef62741 100644 --- a/test/test_metadata_extension.cpp +++ b/test/test_metadata_extension.cpp @@ -9,6 +9,7 @@ #include "libtorrent/extensions/metadata_transfer.hpp" using boost::filesystem::remove_all; +using boost::tuples::ignore; void test_transfer(bool clear_files = true, bool disconnect = false) { @@ -21,7 +22,7 @@ void test_transfer(bool clear_files = true, bool disconnect = false) torrent_handle tor1; torrent_handle tor2; - boost::tie(tor1, tor2) = setup_transfer(ses1, ses2, clear_files); + boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, clear_files); for (int i = 0; i < 50; ++i) { diff --git a/test/test_pe_crypto.cpp b/test/test_pe_crypto.cpp index 144ee3664..cd0d881b4 100644 --- a/test/test_pe_crypto.cpp +++ b/test/test_pe_crypto.cpp @@ -75,6 +75,7 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy, bool pref_rc4 = false) { using namespace libtorrent; + using boost::tuples::ignore; using std::cerr; session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000)); @@ -103,7 +104,7 @@ void test_transfer(libtorrent::pe_settings::enc_policy policy, torrent_handle tor1; torrent_handle tor2; - boost::tie(tor1, tor2) = setup_transfer(ses1, ses2, true, false); + boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, true, false); std::cerr << "waiting for transfer to complete\n"; diff --git a/test/test_swarm.cpp b/test/test_swarm.cpp new file mode 100644 index 000000000..5d07472a7 --- /dev/null +++ b/test/test_swarm.cpp @@ -0,0 +1,129 @@ +#include "libtorrent/session.hpp" +#include "libtorrent/hasher.hpp" +#include +#include +#include + +#include "test.hpp" +#include "setup_transfer.hpp" + +using boost::filesystem::remove_all; + +void test_swarm() +{ + using namespace libtorrent; + + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000)); + session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000)); + session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000)); + + // this is to avoid everything finish from a single peer + // immediately. To make the swarm actually connect all + // three peers before finishing. + float rate_limit = 40000; + ses1.set_upload_rate_limit(int(rate_limit * 1.1)); + ses2.set_download_rate_limit(int(rate_limit)); + ses3.set_download_rate_limit(int(rate_limit)); + ses2.set_upload_rate_limit(int(rate_limit / 2)); + ses3.set_upload_rate_limit(int(rate_limit / 2)); + + session_settings settings; + settings.allow_multiple_connections_per_ip = true; + ses1.set_settings(settings); + ses2.set_settings(settings); + ses3.set_settings(settings); + + pe_settings pes; + pes.out_enc_policy = pe_settings::disabled; + pes.in_enc_policy = pe_settings::disabled; + ses1.set_pe_settings(pes); + ses2.set_pe_settings(pes); + ses3.set_pe_settings(pes); + + torrent_handle tor1; + torrent_handle tor2; + torrent_handle tor3; + + boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false); + + float sum_dl_rate2 = 0.f; + float sum_dl_rate3 = 0.f; + int count_dl_rates2 = 0; + int count_dl_rates3 = 0; + + for (int i = 0; i < 100; ++i) + { + std::auto_ptr a; + a = ses1.pop_alert(); + if (a.get()) + std::cerr << "ses1: " << a->msg() << "\n"; + + a = ses2.pop_alert(); + if (a.get()) + std::cerr << "ses2: " << a->msg() << "\n"; + + a = ses3.pop_alert(); + if (a.get()) + std::cerr << "ses3: " << a->msg() << "\n"; + + torrent_status st1 = tor1.status(); + torrent_status st2 = tor2.status(); + torrent_status st3 = tor3.status(); + + if (st2.progress < 1.f && st2.progress > 0.3f) + { + sum_dl_rate2 += st2.download_payload_rate; + ++count_dl_rates2; + } + if (st3.progress < 1.f && st3.progress > 0.3f) + { + sum_dl_rate3 += st3.download_rate; + ++count_dl_rates3; + } + + std::cerr + << "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s: " + << "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s " + << "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s " + << "\033[0m" << int(st2.progress * 100) << "% - " + << "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s " + << "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s " + << "\033[0m" << int(st3.progress * 100) << "% " + << std::endl; + + if (tor2.is_seed() && tor3.is_seed()) break; + sleep(1000); + } + + TEST_CHECK(tor2.is_seed()); + TEST_CHECK(tor3.is_seed()); + + float average2 = sum_dl_rate2 / float(count_dl_rates2); + float average3 = sum_dl_rate3 / float(count_dl_rates3); + + std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - " + << (average3 / 1000.f) << "kB/s" << std::endl; + +// TEST_CHECK(std::fabs(average2 - float(rate_limit)) < 5000.f); +// TEST_CHECK(std::fabs(average3 - float(rate_limit)) < 5000.f); + if (tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n"; +} + +int test_main() +{ + using namespace libtorrent; + using namespace boost::filesystem; + + remove_all("./tmp1"); + remove_all("./tmp2"); + remove_all("./tmp3"); + + test_swarm(); + + remove_all("./tmp1"); + remove_all("./tmp2"); + remove_all("./tmp3"); + + return 0; +} +