Skip to content

Commit 90ccd51

Browse files
committed
merged RC_1_1 into master
2 parents 5eb9aed + f81a20a commit 90ccd51

9 files changed

+134
-82
lines changed

ChangeLog

+1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
* resume data no longer has timestamps of files
8282
* require C++11 to build libtorrent
8383

84+
* fix loading resume data when in seed mode
8485
* fix part-file creation race condition
8586
* fix issue with initializing settings on session construction
8687
* fix issue with receiving interested before metadata

docs/hunspell/libtorrent.dic

+2
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ pread
8484
preadv
8585
pwrite
8686
pwritev
87+
readv
88+
writev
8789
ftruncate
8890
iovec
8991
uint8

include/libtorrent/storage.hpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,24 @@ namespace libtorrent {
170170
storage_interface(storage_interface const&) = delete;
171171
storage_interface& operator=(storage_interface const&) = delete;
172172

173-
// This function is called when the storage is to be initialized. The
174-
// default storage will create directories and empty files at this point.
175-
// If ``allocate_files`` is true, it will also ``ftruncate`` all files to
176-
// their target size.
173+
// This function is called when the *storage* on disk is to be
174+
// initialized. The default storage will create directories and empty
175+
// files at this point. If ``allocate_files`` is true, it will also
176+
// ``ftruncate`` all files to their target size.
177+
//
178+
// This function may be called multiple time on a single instance. When a
179+
// torrent is force-rechecked, the storage is re-initialized to trigger
180+
// the re-check from scratch.
181+
//
182+
// The function is not necessarily called before other member functions.
183+
// For instance has_any_files() and verify_resume_data() are
184+
// called early to determine whether we may have to check all files or
185+
// not. If we're doing a full check of the files every piece will be
186+
// hashed, causing readv() to be called as well.
187+
//
188+
// Any required internals that need initialization should be done in the
189+
// constructor. This function is called before the torrent starts to
190+
// download.
177191
//
178192
// If an error occurs, ``storage_error`` should be set to reflect it.
179193
virtual void initialize(storage_error& ec) = 0;

src/torrent.cpp

+62-58
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ namespace libtorrent {
573573
m_seed_mode = false;
574574
// seed is false if we turned out not
575575
// to be a seed after all
576-
if (!skip_checking)
576+
if (!skip_checking && state() != torrent_status::checking_resume_data)
577577
{
578578
m_have_all = false;
579579
set_state(torrent_status::downloading);
@@ -1787,80 +1787,78 @@ namespace libtorrent {
17871787
if (m_seed_mode)
17881788
{
17891789
m_have_all = true;
1790-
auto self = shared_from_this();
1791-
m_ses.get_io_service().post([self] { self->wrap(&torrent::files_checked); });
1792-
TORRENT_ASSERT(m_outstanding_check_files == false);
1793-
m_add_torrent_params.reset();
17941790
update_gauge();
17951791
update_state_list();
1796-
return;
17971792
}
1798-
1799-
set_state(torrent_status::checking_resume_data);
1800-
1801-
int num_pad_files = 0;
1802-
TORRENT_ASSERT(block_size() > 0);
1803-
for (file_index_t i(0); i < fs.end_file(); ++i)
1793+
else
18041794
{
1805-
if (fs.pad_file_at(i)) ++num_pad_files;
1795+
int num_pad_files = 0;
1796+
TORRENT_ASSERT(block_size() > 0);
18061797

1807-
if (!fs.pad_file_at(i) || fs.file_size(i) == 0) continue;
1808-
m_padding += std::uint32_t(fs.file_size(i));
1798+
for (file_index_t i(0); i < fs.end_file(); ++i)
1799+
{
1800+
if (fs.pad_file_at(i)) ++num_pad_files;
18091801

1810-
// TODO: instead of creating the picker up front here,
1811-
// maybe this whole section should move to need_picker()
1812-
need_picker();
1802+
if (!fs.pad_file_at(i) || fs.file_size(i) == 0) continue;
1803+
m_padding += std::uint32_t(fs.file_size(i));
18131804

1814-
peer_request pr = m_torrent_file->map_file(i, 0, int(fs.file_size(i)));
1815-
int off = pr.start & (block_size() - 1);
1816-
if (off != 0) { pr.length -= block_size() - off; pr.start += block_size() - off; }
1817-
TORRENT_ASSERT((pr.start & (block_size() - 1)) == 0);
1805+
// TODO: instead of creating the picker up front here,
1806+
// maybe this whole section should move to need_picker()
1807+
need_picker();
18181808

1819-
int block = block_size();
1820-
int blocks_per_piece = m_torrent_file->piece_length() / block;
1821-
piece_block pb(pr.piece, pr.start / block);
1822-
for (; pr.length >= block; pr.length -= block, ++pb.block_index)
1823-
{
1809+
peer_request pr = m_torrent_file->map_file(i, 0, int(fs.file_size(i)));
1810+
int off = pr.start & (block_size() - 1);
1811+
if (off != 0) { pr.length -= block_size() - off; pr.start += block_size() - off; }
1812+
TORRENT_ASSERT((pr.start & (block_size() - 1)) == 0);
1813+
1814+
int block = block_size();
1815+
int blocks_per_piece = m_torrent_file->piece_length() / block;
1816+
piece_block pb(pr.piece, pr.start / block);
1817+
for (; pr.length >= block; pr.length -= block, ++pb.block_index)
1818+
{
1819+
if (pb.block_index == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
1820+
m_picker->mark_as_finished(pb, nullptr);
1821+
}
1822+
// ugly edge case where padfiles are not used they way they're
1823+
// supposed to be. i.e. added back-to back or at the end
18241824
if (pb.block_index == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
1825-
m_picker->mark_as_finished(pb, nullptr);
1825+
if (pr.length > 0 && ((next(i) != fs.end_file() && fs.pad_file_at(next(i)))
1826+
|| next(i) == fs.end_file()))
1827+
{
1828+
m_picker->mark_as_finished(pb, nullptr);
1829+
}
18261830
}
1827-
// ugly edge case where padfiles are not used they way they're
1828-
// supposed to be. i.e. added back-to back or at the end
1829-
if (pb.block_index == blocks_per_piece) { pb.block_index = 0; ++pb.piece_index; }
1830-
if (pr.length > 0 && ((next(i) != fs.end_file() && fs.pad_file_at(next(i)))
1831-
|| next(i) == fs.end_file()))
1831+
1832+
if (m_padding > 0)
18321833
{
1833-
m_picker->mark_as_finished(pb, nullptr);
1834-
}
1835-
}
1834+
// if we marked an entire piece as finished, we actually
1835+
// need to consider it finished
18361836

1837-
if (m_padding > 0)
1838-
{
1839-
// if we marked an entire piece as finished, we actually
1840-
// need to consider it finished
1837+
std::vector<piece_picker::downloading_piece> dq
1838+
= m_picker->get_download_queue();
18411839

1842-
std::vector<piece_picker::downloading_piece> dq
1843-
= m_picker->get_download_queue();
1840+
std::vector<piece_index_t> have_pieces;
18441841

1845-
std::vector<piece_index_t> have_pieces;
1842+
for (auto const& p : dq)
1843+
{
1844+
int const num_blocks = m_picker->blocks_in_piece(p.index);
1845+
if (p.finished < num_blocks) continue;
1846+
have_pieces.push_back(p.index);
1847+
}
18461848

1847-
for (auto const& p : dq)
1848-
{
1849-
int const num_blocks = m_picker->blocks_in_piece(p.index);
1850-
if (p.finished < num_blocks) continue;
1851-
have_pieces.push_back(p.index);
1849+
for (auto i : have_pieces)
1850+
{
1851+
picker().piece_passed(i);
1852+
TORRENT_ASSERT(picker().have_piece(i));
1853+
we_have(i);
1854+
}
18521855
}
18531856

1854-
for (auto i : have_pieces)
1855-
{
1856-
picker().piece_passed(i);
1857-
TORRENT_ASSERT(picker().have_piece(i));
1858-
we_have(i);
1859-
}
1857+
if (num_pad_files > 0)
1858+
m_picker->set_num_pad_files(num_pad_files);
18601859
}
18611860

1862-
if (num_pad_files > 0)
1863-
m_picker->set_num_pad_files(num_pad_files);
1861+
set_state(torrent_status::checking_resume_data);
18641862

18651863
aux::vector<std::string, file_index_t> links;
18661864
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
@@ -2074,7 +2072,13 @@ namespace libtorrent {
20742072
// that when the resume data check fails. For instance, if the resume data
20752073
// is incorrect, but we don't have any files, we skip the check and initialize
20762074
// the storage to not have anything.
2077-
if (status == status_t::no_error)
2075+
if (m_seed_mode)
2076+
{
2077+
m_have_all = true;
2078+
update_gauge();
2079+
update_state_list();
2080+
}
2081+
else if (status == status_t::no_error)
20782082
{
20792083
// there are either no files for this torrent
20802084
// or the resume_data was accepted
@@ -5244,7 +5248,7 @@ namespace libtorrent {
52445248
k = m_trackers.insert(k, url);
52455249
k->endpoints.clear();
52465250
if (k->source == 0) k->source = announce_entry::source_client;
5247-
if (!m_paused && !m_trackers.empty()) announce_with_tracker();
5251+
if (m_announcing && !m_trackers.empty()) announce_with_tracker();
52485252
return true;
52495253
}
52505254

test/test_fast_extension.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,7 @@ std::shared_ptr<torrent_info> setup_peer(tcp::socket& s, sha1_hash& ih
441441
if (th) *th = ret;
442442

443443
// wait for the torrent to be ready
444-
if (!(flags & torrent_flags::seed_mode))
445-
{
446-
wait_for_downloading(*ses, "ses");
447-
}
444+
wait_for_downloading(*ses, "ses");
448445

449446
if (incoming)
450447
{

test/test_priority.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ void test_transfer(settings_pack const& sett, bool test_deprecated = false)
166166
}
167167

168168
TEST_CHECK(st1.state == torrent_status::seeding
169+
|| st1.state == torrent_status::checking_resume_data
169170
|| st1.state == torrent_status::checking_files);
170171
TEST_CHECK(st2.state == torrent_status::downloading
171172
|| st2.state == torrent_status::checking_resume_data);

test/test_remove_torrent.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,13 @@ void test_remove_torrent(remove_flags_t const remove_options
119119
if (st2.is_finished) break;
120120

121121
TEST_CHECK(st1.state == torrent_status::seeding
122+
|| st1.state == torrent_status::checking_resume_data
122123
|| st1.state == torrent_status::checking_files);
123124
TEST_CHECK(st2.state == torrent_status::downloading
124125
|| st2.state == torrent_status::checking_resume_data);
125126

126-
// if nothing is being transferred after 2 seconds, we're failing the test
127-
if (st1.upload_payload_rate == 0 && i > 20)
127+
// if nothing is being transferred after 3 seconds, we're failing the test
128+
if (st1.upload_payload_rate == 0 && i > 30)
128129
{
129130
TEST_ERROR("no transfer");
130131
return;

test/test_resume.cpp

+30
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ void default_tests(torrent_status const& s)
215215
TEST_CHECK(s.active_duration < seconds(1339 + 10));
216216

217217
TEST_CHECK(s.added_time < 1347 + 2);
218+
TEST_CHECK(s.added_time >= 1347);
218219
TEST_CHECK(s.completed_time < 1348 + 2);
220+
TEST_CHECK(s.completed_time >= 1348);
219221
}
220222

221223
void test_piece_priorities(bool test_deprecated = false)
@@ -1056,6 +1058,34 @@ TORRENT_TEST(seed_mode_preserve)
10561058
test_seed_mode(test_mode_t{});
10571059
}
10581060

1061+
TORRENT_TEST(seed_mode_load_peers)
1062+
{
1063+
lt::session ses(settings());
1064+
std::shared_ptr<torrent_info> ti = generate_torrent();
1065+
add_torrent_params p;
1066+
p.ti = ti;
1067+
p.save_path = ".";
1068+
p.flags |= torrent_flags::seed_mode;
1069+
p.peers.push_back(tcp::endpoint(address::from_string("1.2.3.4"), 12345));
1070+
1071+
torrent_handle h = ses.add_torrent(p);
1072+
1073+
wait_for_alert(ses, torrent_checked_alert::alert_type, "seed_mode_load_peers");
1074+
1075+
h.save_resume_data();
1076+
1077+
save_resume_data_alert const* a = alert_cast<save_resume_data_alert>(
1078+
wait_for_alert(ses, save_resume_data_alert::alert_type
1079+
, "seed_mode_load_peers"));
1080+
1081+
TEST_CHECK(a);
1082+
if (a == nullptr) return;
1083+
1084+
auto const& peers = a->params.peers;
1085+
TEST_EQUAL(peers.size(), 1);
1086+
TEST_CHECK(peers[0] == tcp::endpoint(address::from_string("1.2.3.4"), 12345));
1087+
}
1088+
10591089
TORRENT_TEST(resume_save_load)
10601090
{
10611091
lt::session ses(settings());

test/test_tracker.cpp

+16-14
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ TORRENT_TEST(tracker_proxy)
618618
}
619619

620620
#ifndef TORRENT_DISABLE_LOGGING
621-
void test_stop_tracker_timeout(bool nostop)
621+
void test_stop_tracker_timeout(int const timeout)
622622
{
623623
// trick the min interval so that the stopped anounce is permitted immediately
624624
// after the initial announce
@@ -658,8 +658,7 @@ void test_stop_tracker_timeout(bool nostop)
658658
p.set_bool(settings_pack::announce_to_all_tiers, true);
659659
p.set_int(settings_pack::alert_mask, alert::all_categories);
660660
p.set_str(settings_pack::listen_interfaces, "0.0.0.0:6881");
661-
if (nostop)
662-
p.set_int(settings_pack::stop_tracker_timeout, 0);
661+
p.set_int(settings_pack::stop_tracker_timeout, timeout);
663662

664663
lt::session s(p);
665664

@@ -683,28 +682,31 @@ void test_stop_tracker_timeout(bool nostop)
683682
announce_entry ae{tracker_url};
684683
h.add_tracker(ae);
685684

686-
while (true)
687-
{
688-
std::vector<alert*> alerts;
689-
s.pop_alerts(&alerts);
690-
if (std::any_of(alerts.begin(), alerts.end()
691-
, [](alert* a) { return a->type() == tracker_reply_alert::alert_type; }))
692-
break;
693-
}
685+
// make sure it announced a event=started properly
686+
wait_for_alert(s, tracker_reply_alert::alert_type, "s");
694687

695688
s.remove_torrent(h);
696689

690+
wait_for_alert(s, torrent_removed_alert::alert_type, "s");
691+
692+
// we remove and stop the torrent immediately after posting the alert, so we
693+
// need some leeway here
694+
std::this_thread::sleep_for(lt::seconds(2));
695+
697696
int const count = count_stopped_events(s);
698-
TEST_EQUAL(count, nostop ? 0 : 1);
697+
TEST_EQUAL(count, (timeout == 0) ? 0 : 1);
699698
}
700699

701700
TORRENT_TEST(stop_tracker_timeout)
702701
{
703702
std::printf("\n\nexpect to get ONE request with &event=stopped\n\n");
704-
test_stop_tracker_timeout(false);
703+
test_stop_tracker_timeout(1);
704+
}
705705

706+
TORRENT_TEST(stop_tracker_timeout_zero_timeout)
707+
{
706708
std::printf("\n\nexpect to NOT get a request with &event=stopped\n\n");
707-
test_stop_tracker_timeout(true);
709+
test_stop_tracker_timeout(0);
708710
}
709711
#endif
710712

0 commit comments

Comments
 (0)