mirror of
https://github.com/arvidn/libtorrent.git
synced 2026-05-07 00:10:28 -04:00
275 lines
7.9 KiB
C++
275 lines
7.9 KiB
C++
/*
|
|
|
|
Copyright (c) 2016-2022, Arvid Norberg
|
|
Copyright (c) 2017, Steven Siloti
|
|
Copyright (c) 2021, Alden Torres
|
|
All rights reserved.
|
|
|
|
You may use, distribute and modify this code under the terms of the BSD license,
|
|
see LICENSE file.
|
|
*/
|
|
|
|
#include "libtorrent/session.hpp"
|
|
#include "libtorrent/aux_/deadline_timer.hpp"
|
|
#include "libtorrent/address.hpp"
|
|
#include "libtorrent/torrent_status.hpp"
|
|
#include "libtorrent/torrent_info.hpp"
|
|
#include "libtorrent/aux_/file.hpp"
|
|
#include "libtorrent/create_torrent.hpp"
|
|
#include "libtorrent/hex.hpp"
|
|
#include "simulator/simulator.hpp"
|
|
#include "simulator/utils.hpp"
|
|
#include "libtorrent/load_torrent.hpp"
|
|
|
|
#include "test.hpp"
|
|
#include "settings.hpp"
|
|
#include "setup_transfer.hpp" // for create_random_files
|
|
#include "create_torrent.hpp"
|
|
#include "utils.hpp"
|
|
#include "test_utils.hpp"
|
|
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
template <typename Setup, typename Test>
|
|
void run_test(Setup const& setup, Test const& test)
|
|
{
|
|
// this is a seeding torrent
|
|
lt::add_torrent_params atp = create_torrent(0, true);
|
|
|
|
sim::default_config network_cfg;
|
|
sim::simulation sim{network_cfg};
|
|
auto ios = std::make_unique<sim::asio::io_context>(
|
|
sim, lt::make_address_v4("50.0.0.1"));
|
|
lt::session_proxy zombie;
|
|
|
|
// setup settings pack to use for the session (customization point)
|
|
lt::settings_pack pack = settings();
|
|
setup(atp, pack);
|
|
|
|
auto ses = std::make_shared<lt::session>(pack, *ios);
|
|
|
|
ses->async_add_torrent(atp);
|
|
|
|
print_alerts(*ses);
|
|
|
|
sim::timer t(sim, lt::seconds(6), [&](boost::system::error_code const&)
|
|
{
|
|
test(*ses);
|
|
|
|
// shut down
|
|
zombie = ses->abort();
|
|
ses.reset();
|
|
});
|
|
|
|
sim.run();
|
|
}
|
|
|
|
template <typename SetupTorrent, typename SetupFiles, typename Test>
|
|
void run_force_recheck_test(SetupTorrent const& setup1, SetupFiles const& setup2, Test const& test)
|
|
{
|
|
// this is a seeding torrent
|
|
lt::add_torrent_params atp = create_torrent(0, true);
|
|
|
|
sim::default_config network_cfg;
|
|
sim::simulation sim{network_cfg};
|
|
auto ios = std::make_unique<sim::asio::io_context>(
|
|
sim, lt::make_address_v4("50.0.0.1"));
|
|
lt::session_proxy zombie;
|
|
|
|
// setup settings pack to use for the session (customization point)
|
|
lt::settings_pack pack = settings();
|
|
setup1(atp, pack);
|
|
|
|
auto ses = std::make_shared<lt::session>(pack, *ios);
|
|
|
|
ses->async_add_torrent(atp);
|
|
|
|
print_alerts(*ses);
|
|
|
|
sim::timer t1(sim, lt::seconds(6), [&](boost::system::error_code const&)
|
|
{
|
|
setup2(atp);
|
|
ses->get_torrents()[0].force_recheck();
|
|
});
|
|
|
|
sim::timer t2(sim, lt::seconds(12), [&](boost::system::error_code const&)
|
|
{
|
|
test(*ses);
|
|
|
|
// shut down
|
|
zombie = ses->abort();
|
|
ses.reset();
|
|
});
|
|
|
|
sim.run();
|
|
}
|
|
|
|
TORRENT_TEST(no_truncate_checking)
|
|
{
|
|
std::string filename;
|
|
int size = 0;
|
|
run_test(
|
|
[&](lt::add_torrent_params& atp, lt::settings_pack&) {
|
|
filename = lt::combine_path(atp.save_path, atp.ti->layout().file_path(lt::file_index_t{0}));
|
|
std::ofstream f(filename);
|
|
// create a file that's 100 bytes larger
|
|
size = int(atp.ti->layout().file_size(lt::file_index_t{0}) + 100);
|
|
std::vector<char> dummy(size);
|
|
f.write(dummy.data(), dummy.size());
|
|
},
|
|
[](lt::session&) {}
|
|
);
|
|
|
|
// file should not have been truncated just by checking
|
|
std::ifstream f(filename);
|
|
f.seekg(0, std::ios_base::end);
|
|
TEST_EQUAL(f.tellg(), std::fstream::pos_type(size));
|
|
}
|
|
|
|
lt::add_torrent_params create_multifile_torrent()
|
|
{
|
|
// the two first files are exactly the size of a piece
|
|
static std::array<const int, 8> const file_sizes{{ 0x40000, 0x40000, 4300, 0, 400, 4300, 6, 4}};
|
|
|
|
auto fs = create_random_files("test_torrent_dir", file_sizes);
|
|
// the torrent needs to be v1 only because the zero_priority_missing_partfile
|
|
// test relies on non-aligned files
|
|
lt::create_torrent t(std::move(fs), 0x40000, lt::create_torrent::v1_only);
|
|
|
|
// calculate the hash for all pieces
|
|
set_piece_hashes(t, ".");
|
|
|
|
std::vector<char> const buf = lt::bencode(t.generate());
|
|
return lt::load_torrent_buffer(buf);
|
|
}
|
|
|
|
TORRENT_TEST(checking_first_piece_missing)
|
|
{
|
|
run_force_recheck_test(
|
|
[&](lt::add_torrent_params&, lt::settings_pack& pack) {
|
|
pack.set_int(lt::settings_pack::checking_mem_usage, 1);
|
|
},
|
|
[&](lt::add_torrent_params& atp) {
|
|
std::string filename = lt::combine_path(
|
|
atp.save_path, atp.ti->layout().file_path(lt::file_index_t{0}));
|
|
FILE* f = ::fopen(filename.c_str(), "rb+");
|
|
::fwrite("0000", 4, 1, f);
|
|
::fclose(f);
|
|
},
|
|
[](lt::session& ses) {
|
|
lt::torrent_handle tor = ses.get_torrents()[0];
|
|
lt::torrent_status st = tor.status(lt::torrent_handle::query_pieces);
|
|
|
|
TEST_EQUAL(st.is_finished, false);
|
|
|
|
|
|
lt::typed_bitfield<lt::piece_index_t> expected_pieces(st.pieces.size(), true);
|
|
expected_pieces.clear_bit(0_piece);
|
|
|
|
// check that just the first piece is missing
|
|
for (lt::piece_index_t p : expected_pieces.range())
|
|
TEST_EQUAL(st.pieces[p], expected_pieces[p]);
|
|
}
|
|
);
|
|
}
|
|
|
|
TORRENT_TEST(aligned_zero_priority)
|
|
{
|
|
run_test(
|
|
[&](lt::add_torrent_params& atp, lt::settings_pack&) {
|
|
atp = create_multifile_torrent();
|
|
atp.file_priorities.push_back(lt::download_priority_t{1});
|
|
atp.file_priorities.push_back(lt::download_priority_t{0});
|
|
atp.save_path = ".";
|
|
},
|
|
[](lt::session& ses) {
|
|
std::vector<lt::torrent_handle> tor = ses.get_torrents();
|
|
TEST_EQUAL(tor.size(), 1);
|
|
TEST_EQUAL(tor[0].status().is_finished, true);
|
|
}
|
|
);
|
|
}
|
|
|
|
// we have a zero-priority file that also does not exist on disk. It does not
|
|
// overlap any piece in another file, so we don't need a partfile
|
|
TORRENT_TEST(aligned_zero_priority_no_file)
|
|
{
|
|
std::string partfile;
|
|
run_test(
|
|
[&](lt::add_torrent_params& atp, lt::settings_pack&) {
|
|
atp = create_multifile_torrent();
|
|
atp.save_path = ".";
|
|
atp.file_priorities.push_back(lt::download_priority_t{1});
|
|
atp.file_priorities.push_back(lt::download_priority_t{0});
|
|
std::string filename = lt::combine_path(lt::current_working_directory()
|
|
, lt::combine_path(atp.save_path, atp.ti->layout().file_path(lt::file_index_t{1})));
|
|
partfile = lt::combine_path(lt::current_working_directory()
|
|
, lt::combine_path(atp.save_path, "." + lt::aux::to_hex(atp.ti->info_hashes().v1.to_string()) + ".parts"));
|
|
lt::error_code ec;
|
|
lt::remove(filename, ec);
|
|
TEST_CHECK(!ec);
|
|
},
|
|
[](lt::session& ses) {
|
|
std::vector<lt::torrent_handle> tor = ses.get_torrents();
|
|
TEST_EQUAL(tor.size(), 1);
|
|
TEST_EQUAL(tor[0].status().is_finished, true);
|
|
}
|
|
);
|
|
|
|
// the part file should not have been created. There is no need for a
|
|
// partfile
|
|
lt::error_code ec;
|
|
lt::file_status fs;
|
|
stat_file(partfile, &fs, ec);
|
|
TEST_EQUAL(ec, boost::system::errc::no_such_file_or_directory);
|
|
}
|
|
|
|
// we have a file whose priority is 0, we don't have the file on disk nor a
|
|
// part-file for it. The checking should complete and enter download state.
|
|
TORRENT_TEST(zero_priority_missing_partfile)
|
|
{
|
|
lt::add_torrent_params addp = create_multifile_torrent();
|
|
run_test(
|
|
[&](lt::add_torrent_params& atp, lt::settings_pack&) {
|
|
atp = addp;
|
|
atp.save_path = ".";
|
|
atp.file_priorities.push_back(lt::download_priority_t{1});
|
|
atp.file_priorities.push_back(lt::download_priority_t{1});
|
|
atp.file_priorities.push_back(lt::download_priority_t{0});
|
|
std::string const filename = lt::combine_path(lt::current_working_directory()
|
|
, lt::combine_path(atp.save_path, atp.ti->layout().file_path(lt::file_index_t{2})));
|
|
|
|
std::cout << "removing: " << filename << "\n";
|
|
lt::error_code ec;
|
|
lt::remove(filename, ec);
|
|
TEST_CHECK(!ec);
|
|
},
|
|
[&](lt::session& ses) {
|
|
std::vector<lt::torrent_handle> tor = ses.get_torrents();
|
|
TEST_EQUAL(tor.size(), 1);
|
|
TEST_EQUAL(tor[0].status().num_pieces, addp.ti->num_pieces() - 1);
|
|
TEST_EQUAL(tor[0].status().is_finished, false);
|
|
}
|
|
);
|
|
}
|
|
|
|
TORRENT_TEST(checking)
|
|
{
|
|
run_test(
|
|
[](lt::add_torrent_params& atp, lt::settings_pack& p) {
|
|
atp.flags |= lt::torrent_flags::auto_managed;
|
|
#if TORRENT_ABI_VERSION == 1
|
|
p.set_int(lt::settings_pack::cache_size, 100);
|
|
#endif
|
|
},
|
|
[](lt::session& ses) {
|
|
|
|
std::vector<lt::torrent_handle> tor = ses.get_torrents();
|
|
TEST_EQUAL(tor.size(), 1);
|
|
|
|
TEST_EQUAL(tor[0].status().is_seeding, true);
|
|
});
|
|
}
|
|
|