diff --git a/src/torrent.cpp b/src/torrent.cpp index 4f7b7ee1d..a5e394c8c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1800,7 +1800,6 @@ namespace libtorrent INVARIANT_CHECK; if (m_torrent_file->num_pieces() == 0) return; - bool was_finished = is_finished(); size_type position = 0; int piece_length = m_torrent_file->piece_length(); @@ -1826,7 +1825,6 @@ namespace libtorrent , bind(&set_if_greater, _1, m_file_priority[i])); } prioritize_pieces(pieces); - update_peer_interest(was_finished); } // this is called when piece priorities have been updated @@ -1836,16 +1834,18 @@ namespace libtorrent for (peer_iterator i = begin(); i != end(); ++i) (*i)->update_interest(); - // if we used to be finished, but we aren't anymore - // we may need to connect to peers again - if (!is_finished() && was_finished) - m_policy.recalculate_connect_candidates(); - // the torrent just became finished if (is_finished() && !was_finished) + { finished(); + } else if (!is_finished() && was_finished) + { + // if we used to be finished, but we aren't anymore + // we may need to connect to peers again resume_download(); + m_policy.recalculate_connect_candidates(); + } } void torrent::filter_piece(int index, bool filter) @@ -3147,9 +3147,9 @@ namespace libtorrent // to make sure we're cleared the piece picker if (is_seed()) completed(); - // disconnect all seeds - // TODO: should disconnect all peers that have the pieces we have - // not just seeds + // disconnect all seeds + // TODO: should disconnect all peers that have the pieces we have + // not just seeds std::vector seeds; for (peer_iterator i = m_connections.begin(); i != m_connections.end(); ++i) @@ -3265,6 +3265,12 @@ namespace libtorrent set_state(torrent_status::downloading); + if (m_ses.m_alerts.should_post()) + { + m_ses.m_alerts.post_alert(torrent_checked_alert( + get_handle())); + } + if (!is_seed()) { if (m_sequential_download) @@ -3274,6 +3280,13 @@ namespace libtorrent // likely to be unpaused if (m_ses.m_auto_manage_time_scaler > 1) m_ses.m_auto_manage_time_scaler = 1; + + if (is_finished()) finished(); + } + else + { + m_complete_sent = true; + finished(); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -3290,12 +3303,6 @@ namespace libtorrent } #endif - if (is_seed()) - { - m_complete_sent = true; - finished(); - } - if (!m_connections_initialized) { m_connections_initialized = true; @@ -3311,12 +3318,6 @@ namespace libtorrent } } - if (m_ses.m_alerts.should_post()) - { - m_ses.m_alerts.post_alert(torrent_checked_alert( - get_handle())); - } - m_files_checked = true; start_announcing(); diff --git a/test/Jamfile b/test/Jamfile index 8b16255f7..0392f71bd 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -34,6 +34,7 @@ test-suite libtorrent : [ run test_buffer.cpp ] [ run test_storage.cpp ] [ run test_torrent.cpp ] + [ run test_transfer.cpp ] [ run test_piece_picker.cpp ] # [ run test_entry.cpp ] [ run test_fast_extension.cpp ] diff --git a/test/Makefile.am b/test/Makefile.am index eb0728d28..8b1745326 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,7 +1,7 @@ check_PROGRAMS = test_hasher test_bencoding test_ip_filter test_piece_picker \ test_storage test_metadata_extension test_buffer test_swarm test_pe_crypto test_primitives \ test_bandwidth_limiter test_upnp test_fast_extension test_pex test_web_seed \ -test_http_connection test_lsd +test_http_connection test_torrent test_transfer test_lsd TESTS = $(check_PROGRAMS) @@ -61,6 +61,9 @@ test_bandwidth_limiter_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la test_torrent_SOURCES = main.cpp test_torrent.cpp test_torrent_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la +test_transfer_SOURCES = main.cpp test_transfer.cpp +test_transfer_LDADD = $(top_builddir)/src/libtorrent-rasterbar.la + noinst_HEADERS = test.hpp setup_transfer.hpp AM_CXXFLAGS=-ftemplate-depth-50 -I$(top_srcdir)/include -I$(top_srcdir)/include/libtorrent @DEBUGFLAGS@ @PTHREAD_CFLAGS@ -DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index c0698f7b0..ad708221f 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -236,7 +236,8 @@ boost::intrusive_ptr create_torrent(std::ostream* file, int piece_ boost::tuple setup_transfer(session* ses1, session* ses2, session* ses3 , bool clear_files, bool use_metadata_transfer, bool connect_peers - , std::string suffix, int piece_size) + , std::string suffix, int piece_size + , boost::intrusive_ptr* torrent) { using namespace boost::filesystem; @@ -247,18 +248,24 @@ setup_transfer(session* ses1, session* ses2, session* ses3 if (ses3) assert(ses3->id() != ses2->id()); - - create_directory("./tmp1" + suffix); - std::ofstream file(("./tmp1" + suffix + "/temporary").c_str()); - boost::intrusive_ptr t = ::create_torrent(&file, piece_size); - file.close(); - if (clear_files) + boost::intrusive_ptr t; + if (torrent == 0) { - remove_all("./tmp2" + suffix + "/temporary"); - remove_all("./tmp3" + suffix + "/temporary"); + create_directory("./tmp1" + suffix); + std::ofstream file(("./tmp1" + suffix + "/temporary").c_str()); + t = ::create_torrent(&file, piece_size); + file.close(); + if (clear_files) + { + remove_all("./tmp2" + suffix + "/temporary"); + remove_all("./tmp3" + suffix + "/temporary"); + } + std::cerr << "generated torrent: " << t->info_hash() << std::endl; + } + else + { + t = *torrent; } - - std::cerr << "generated torrent: " << t->info_hash() << std::endl; ses1->set_severity_level(alert::debug); ses2->set_severity_level(alert::debug); diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 11a282446..ed2684d2d 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -48,7 +48,8 @@ boost::tuple setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2 , libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true - , bool connect = true, std::string suffix = "", int piece_size = 16 * 1024); + , bool connect = true, std::string suffix = "", int piece_size = 16 * 1024 + , boost::intrusive_ptr* torrent = 0); void start_web_server(int port, bool ssl = false); void stop_web_server(int port); diff --git a/test/test_transfer.cpp b/test/test_transfer.cpp new file mode 100644 index 000000000..76264f626 --- /dev/null +++ b/test/test_transfer.cpp @@ -0,0 +1,198 @@ +/* + +Copyright (c) 2008, 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. + +*/ + +#include "libtorrent/session.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/hasher.hpp" +#include "libtorrent/alert_types.hpp" +#include "libtorrent/bencode.hpp" +#include +#include +#include + +#include "test.hpp" +#include "setup_transfer.hpp" + +using boost::filesystem::remove_all; +using boost::filesystem::exists; +using boost::filesystem::create_directory; + +void test_transfer() +{ + using namespace libtorrent; + using boost::tuples::ignore; + + session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000)); + session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000)); + +#ifndef TORRENT_DISABLE_ENCRYPTION + pe_settings pes; + pes.out_enc_policy = pe_settings::forced; + pes.in_enc_policy = pe_settings::forced; + ses1.set_pe_settings(pes); + ses2.set_pe_settings(pes); +#endif + + torrent_handle tor1; + torrent_handle tor2; + + create_directory("./tmp1_transfer"); + std::ofstream file("./tmp1_transfer/temporary"); + boost::intrusive_ptr t = ::create_torrent(&file, 16 * 1024); + file.close(); + + // test using piece sizes smaller than 16kB + boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0 + , true, false, true, "_transfer", 8 * 1024, &t); + + // set half of the pieces to priority 0 + int num_pieces = tor2.get_torrent_info().num_pieces(); + std::vector priorities(num_pieces, 1); + std::fill(priorities.begin(), priorities.begin() + num_pieces / 2, 0); + tor2.prioritize_pieces(priorities); + + ses1.set_alert_mask(alert::all_categories & ~alert::progress_notification); + ses2.set_alert_mask(alert::all_categories & ~alert::progress_notification); + + tor1.resume(); + tor2.resume(); + + for (int i = 0; i < 30; ++i) + { + print_alerts(ses1, "ses1"); + print_alerts(ses2, "ses2"); + + torrent_status st1 = tor1.status(); + torrent_status st2 = tor2.status(); + + std::cerr + << "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s " + << "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s " + << "\033[0m" << int(st1.progress * 100) << "% " + << st1.num_peers + << ": " + << "\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) << "% " + << st2.num_peers + << std::endl; + + if (tor2.is_finished()) break; + + TEST_CHECK(st1.state == torrent_status::seeding); + TEST_CHECK(st2.state == torrent_status::downloading); + + test_sleep(1000); + } + + TEST_CHECK(!tor2.is_seed()); + std::cerr << "torrent is finished (50% complete)" << std::endl; + + tor2.pause(); + alert const* a = ses2.wait_for_alert(seconds(10)); + while (a) + { + std::auto_ptr holder = ses2.pop_alert(); + std::cerr << "ses2: " << a->message() << std::endl; + if (dynamic_cast(a)) break; + a = ses2.wait_for_alert(seconds(10)); + } + + tor2.save_resume_data(); + + std::vector resume_data; + a = ses2.wait_for_alert(seconds(10)); + while (a) + { + std::auto_ptr holder = ses2.pop_alert(); + std::cerr << "ses2: " << a->message() << std::endl; + if (dynamic_cast(a)) + { + bencode(std::back_inserter(resume_data) + , *dynamic_cast(a)->resume_data); + break; + } + a = ses2.wait_for_alert(seconds(10)); + } + + std::cerr << "saved resume data" << std::endl; + + ses2.remove_torrent(tor2); + + std::cerr << "removed" << std::endl; + + test_sleep(1000); + + std::cout << "re-adding" << std::endl; + add_torrent_params p; + p.ti = t; + p.save_path = "./tmp2_transfer"; + p.resume_data = &resume_data; + tor2 = ses2.add_torrent(p); + tor2.prioritize_pieces(priorities); + std::cout << "resetting priorities" << std::endl; + tor2.resume(); + + test_sleep(1000); + + for (int i = 0; i < 5; ++i) + { + print_alerts(ses1, "ses1"); + print_alerts(ses2, "ses2"); + + torrent_status st1 = tor1.status(); + torrent_status st2 = tor2.status(); + + TEST_CHECK(st1.state == torrent_status::seeding); + TEST_CHECK(st2.state == torrent_status::finished); + + test_sleep(1000); + } + + TEST_CHECK(!tor2.is_seed()); + +} + +int test_main() +{ + using namespace libtorrent; + using namespace boost::filesystem; + + // in case the previous run was terminated + try { remove_all("./tmp1_transfer"); } catch (std::exception&) {} + try { remove_all("./tmp2_transfer"); } catch (std::exception&) {} + + test_transfer(); + + return 0; +} +