diff --git a/ChangeLog b/ChangeLog index f93969b4d..b64a62145 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix last_upload and last_download overflow after 9 hours in past * python binding add more add_torrent_params fields and an invalid key check * introduce introduce distinct types for peer_class_t, piece_index_t and file_index_t. diff --git a/bindings/python/test.py b/bindings/python/test.py index a2addd244..5dd959c29 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -5,6 +5,7 @@ import libtorrent as lt import unittest import time +import datetime import os import shutil import binascii @@ -80,6 +81,18 @@ class test_torrent_handle(unittest.TestCase): self.setup() self.h.clear_piece_deadlines() + def test_status_last_uploaded_dowloaded(self): + # we want to check at seconds precision but can't control session + # time, wait for next full second to prevent second increment + time.sleep(1 - datetime.datetime.now().microsecond / 1000000.0) + + sessionStart = datetime.datetime.now().replace(microsecond=0) + self.setup() + st = self.h.status() + # last upload and download times are at session start time + self.assertEqual(st.last_upload, sessionStart) + self.assertEqual(st.last_download, sessionStart) + def test_torrent_status(self): self.setup() st = self.h.status() @@ -268,6 +281,7 @@ class test_alerts(unittest.TestCase): 'enable_dht': False}) ses.async_add_torrent( {"ti": lt.torrent_info("base.torrent"), "save_path": "."}) + # this will cause an error (because of duplicate torrents) and the # torrent_info object created here will be deleted once the alert goes out # of scope. When that happens, it will decrement the python object, to allow diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index cb562a694..4a978592a 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -95,6 +95,8 @@ namespace libtorrent class bt_peer_connection; struct listen_socket_t; + using seconds32 = std::chrono::duration; + enum class waste_reason { piece_timed_out, piece_cancelled, piece_unknown, piece_seed @@ -478,14 +480,15 @@ namespace libtorrent void stop_when_ready(bool b); - int started() const { return m_started; } + time_point started() const { return m_started; } void step_session_time(int seconds); void do_pause(bool clear_disk_cache = true); void do_resume(); - int finished_time() const; - int active_time() const; - int seeding_time() const; + seconds32 finished_time() const; + seconds32 active_time() const; + seconds32 seeding_time() const; + seconds32 upload_mode_time() const; bool is_paused() const; bool is_torrent_paused() const { return m_paused; } @@ -496,7 +499,8 @@ namespace libtorrent { // save resume data every 15 minutes regardless, just to // keep stats up to date - return m_need_save_resume_data || m_ses.session_time() - m_last_saved_resume > 15 * 60; + return m_need_save_resume_data || + aux::time_now() - m_last_saved_resume > minutes(15); } void set_need_save_resume() @@ -1034,7 +1038,7 @@ namespace libtorrent // that are not private void lsd_announce(); - void update_last_upload() { m_last_upload = int16_t(m_ses.session_time()); } + void update_last_upload() { m_last_upload = aux::time_now(); } void set_apply_ip_filter(bool b); bool apply_ip_filter() const { return m_apply_ip_filter; } @@ -1314,9 +1318,7 @@ namespace libtorrent // m_num_verified = m_verified.count() std::uint32_t m_num_verified = 0; - // this timestamp is kept in session-time, to - // make it fit in 16 bits - std::uint16_t m_last_saved_resume; + time_point m_last_saved_resume = aux::time_now(); // if this torrent is running, this was the time // when it was started. This is used to have a @@ -1326,15 +1328,15 @@ namespace libtorrent // in session-time. see session_impl for details. // the reference point is stepped forward every 4 // hours to keep the timestamps fit in 16 bits - std::uint16_t m_started; + time_point m_started = aux::time_now(); // if we're a seed, this is the session time // timestamp of when we became one - std::uint16_t m_became_seed = 0; + time_point m_became_seed = aux::time_now(); // if we're finished, this is the session time // timestamp of when we finished - std::uint16_t m_became_finished = 0; + time_point m_became_finished = aux::time_now(); // when checking, this is the first piece we have not // issued a hash job for @@ -1383,7 +1385,7 @@ namespace libtorrent // the session time timestamp of when we entered upload mode // if we're currently in upload-mode - std::uint16_t m_upload_mode_time = 0; + time_point m_upload_mode_time = aux::time_now(); // true when this torrent should announce to // trackers @@ -1425,7 +1427,7 @@ namespace libtorrent // paused. specified in seconds. This only track time _before_ we started // the torrent this last time. When the torrent is paused, this counter is // incremented to include this current session. - unsigned int m_active_time:24; + seconds32 m_active_time; // the index to the last tracker that worked std::int8_t m_last_working_tracker = -1; @@ -1434,7 +1436,7 @@ namespace libtorrent // total time we've been finished with this torrent. // does not count when the torrent is stopped or paused. - unsigned int m_finished_time:24; + seconds32 m_finished_time; // in case the piece picker hasn't been constructed // when this settings is set, this variable will keep @@ -1474,7 +1476,7 @@ namespace libtorrent // accounts for the time prior to the current start of the torrent. When // the torrent is paused, this counter is incremented to account for the // additional seeding time. - unsigned int m_seeding_time:24; + seconds32 m_seeding_time; // ---- @@ -1562,7 +1564,7 @@ namespace libtorrent // the timestamp of the last piece passed for this torrent specified in // session_time. This is signed because it must be able to represent time // before the session started - std::int16_t m_last_download = (std::numeric_limits::min)(); + time_point m_last_download = aux::time_now(); // the number of peer connections to seeds. This should be the same as // counting the peer connections that say true for is_seed() @@ -1575,7 +1577,7 @@ namespace libtorrent // the timestamp of the last byte uploaded from this torrent specified in // session_time. This is signed because it must be able to represent time // before the session started. - std::int16_t m_last_upload = (std::numeric_limits::min)(); + time_point m_last_upload = aux::time_now(); // ---- diff --git a/include/libtorrent/torrent_status.hpp b/include/libtorrent/torrent_status.hpp index dbde6be93..4c067e787 100644 --- a/include/libtorrent/torrent_status.hpp +++ b/include/libtorrent/torrent_status.hpp @@ -546,7 +546,9 @@ namespace libtorrent // the info-hash for this torrent sha1_hash info_hash; + // This value is not persistent and get set to session start time. time_point last_upload; + // This value is not persistent and get set to session start time. time_point last_download; seconds active_duration; diff --git a/simulation/test_torrent_status.cpp b/simulation/test_torrent_status.cpp index 6e1bb25e5..88b02a81d 100644 --- a/simulation/test_torrent_status.cpp +++ b/simulation/test_torrent_status.cpp @@ -79,24 +79,294 @@ TORRENT_TEST(status_timers) if ((ticks % 3600) == 0) { lt::time_point const now = lt::clock_type::now(); - auto const since_start = duration_cast(now - start_time) - lt::seconds(1); + // finish is 1 tick after start + auto const since_finish = duration_cast(now - start_time) - lt::seconds(1); torrent_status st = handle.status(); - TEST_CHECK(st.active_duration == since_start); - TEST_CHECK(st.seeding_duration == since_start); - TEST_CHECK(st.finished_duration == since_start); - TEST_CHECK(st.last_upload < start_time); + TEST_EQUAL(st.active_duration.count(), since_finish.count()); + TEST_EQUAL(st.seeding_duration.count(), since_finish.count()); + TEST_EQUAL(st.finished_duration.count(), since_finish.count()); - // checking the torrent counts as downloading - // eventually though, we've forgotten about it and go back to -1 - if (since_start > lt::seconds(65000)) - { - TEST_CHECK(st.last_download < start_time); - } - else - { - // TODO: this should really be a proximity-check - TEST_CHECK(st.last_download == start_time + lt::seconds(1)); - } + // does not upload without peers + TEST_CHECK(st.last_upload == start_time); + // does not download in seeding mode + TEST_CHECK(st.last_download == start_time); + } + return false; + }); + TEST_CHECK(ran_to_completion); +} + +TORRENT_TEST(status_timers_last_upload) +{ + bool ran_to_completion = false; + + lt::time_point start_time; + lt::torrent_handle handle; + + setup_swarm(2, swarm_test::upload + // add session + , [](lt::settings_pack&) {} + // add torrent + , [](lt::add_torrent_params&) {} + // on alert + , [&](lt::alert const* a, lt::session&) { + if (auto ta = alert_cast(a)) + { + TEST_CHECK(!handle.is_valid()); + start_time = lt::clock_type::now(); + handle = ta->handle; + torrent_status st = handle.status(); + // test last upload and download state before wo go throgh + // torrent states + TEST_CHECK(st.last_download == start_time); + TEST_CHECK(st.last_upload == start_time); + } + } + // terminate + , [&](int ticks, lt::session&) -> bool + { + if (ticks > 10) + { + ran_to_completion = true; + return true; + } + + torrent_status st = handle.status(); + // uploadtime is 0 seconds behind now + TEST_EQUAL(duration_cast(st.last_upload - lt::clock_type::now()).count(), 0); + // does not download in seeding mode + TEST_CHECK(st.last_download == start_time); + return false; + }); + TEST_CHECK(ran_to_completion); +} + +TORRENT_TEST(status_timers_time_shift_with_active_torrent) +{ + bool ran_to_completion = false; + + lt::time_point start_time; + lt::torrent_handle handle; + seconds expected_active_duration = seconds(0); + bool tick_is_in_active_range = false; + int tick_check_intervall = 1; + + setup_swarm(1, swarm_test::upload + // add session + , [](lt::settings_pack&) {} + // add torrent + , [](lt::add_torrent_params&) {} + // on alert + , [&](lt::alert const* a, lt::session&) { + if (auto ta = alert_cast(a)) + { + TEST_CHECK(!handle.is_valid()); + start_time = lt::clock_type::now(); + handle = ta->handle; + torrent_status st = handle.status(); + // test last upload and download state before wo go throgh + // torrent states + TEST_CHECK(st.last_download == start_time); + TEST_CHECK(st.last_upload == start_time); + } + } + // terminate + , [&](int ticks, lt::session&) -> bool + { + if(tick_is_in_active_range){ + // 1 second per tick + expected_active_duration++; + } + + switch(ticks) + { + case 0: + // torrent get ready for seeding on first tick, means time +1s + tick_is_in_active_range = true; + break; + case 1: + // pause after we did have the first upload tick + handle.pause(); + tick_is_in_active_range = false; + break; + case 64000: + // resume just before we hit the time shift handling + // this is needed to test what happend if we want to + // shift more time then we have active time because + // we shift 4 hours and have less then 1 hours active time + handle.resume(); + tick_is_in_active_range = true; + // don't check every tick + tick_check_intervall = 600; + break; + case 68000: + // simulate at least 68000 seconds because timestamps are + // 16 bits counting seconds + ran_to_completion = true; + return true; + } + + // verify that the timers seem correct + if (tick_is_in_active_range && (ticks % tick_check_intervall) == 0) + { + torrent_status st = handle.status(); + TEST_EQUAL(st.active_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count()); + // does not upload without peers + TEST_CHECK(st.last_upload == start_time); + // does not download in seeding mode + TEST_CHECK(st.last_download == start_time); + } + return false; + }); + TEST_CHECK(ran_to_completion); +} + +TORRENT_TEST(finish_time_shift_active) +{ + bool ran_to_completion = false; + + lt::time_point start_time; + lt::torrent_handle handle; + seconds expected_active_duration = seconds(0); + bool tick_is_in_active_range = false; + + setup_swarm(1, swarm_test::upload + // add session + , [](lt::settings_pack&) {} + // add torrent + , [](lt::add_torrent_params&) {} + // on alert + , [&](lt::alert const* a, lt::session&) { + if (auto ta = alert_cast(a)) + { + TEST_CHECK(!handle.is_valid()); + start_time = lt::clock_type::now(); + handle = ta->handle; + torrent_status st = handle.status(); + // test last upload and download state before wo go throgh + // torrent states + TEST_CHECK(st.last_download == start_time); + TEST_CHECK(st.last_upload == start_time); + } + } + // terminate + , [&](int ticks, lt::session&) -> bool + { + if(tick_is_in_active_range){ + // 1 second per tick + expected_active_duration++; + } + + switch(ticks) + { + case 0: + // torrent get ready for seeding on first tick, means time +1s + tick_is_in_active_range = true; + break; + case 7000: + // pause before 4 hours to get a become finish timestamp which + // will be clamped + handle.pause(); + // resume to get an become finish update + handle.resume(); + tick_is_in_active_range = true; + break; + case 70000: + // simulate at least 70000 seconds because timestamps are + // 16 bits counting seconds + ran_to_completion = true; + return true; + } + + // verify that the timers seem correct + if ((ticks % 3600) == 0) + { + torrent_status st = handle.status(); + TEST_EQUAL(st.active_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count()); + // does not upload without peers + TEST_CHECK(st.last_upload == start_time); + // does not download in seeding mode + TEST_CHECK(st.last_download == start_time); + } + return false; + }); + TEST_CHECK(ran_to_completion); +} + +TORRENT_TEST(finish_time_shift_paused) +{ + bool ran_to_completion = false; + + lt::time_point start_time; + lt::torrent_handle handle; + seconds expected_active_duration = seconds(0); + bool tick_is_in_active_range = false; + + setup_swarm(1, swarm_test::upload + // add session + , [](lt::settings_pack&) {} + // add torrent + , [](lt::add_torrent_params&) {} + // on alert + , [&](lt::alert const* a, lt::session&) { + if (auto ta = alert_cast(a)) + { + TEST_CHECK(!handle.is_valid()); + start_time = lt::clock_type::now(); + handle = ta->handle; + torrent_status st = handle.status(); + // test last upload and download state before wo go throgh + // torrent states + TEST_CHECK(st.last_download == start_time); + TEST_CHECK(st.last_upload == start_time); + } + } + // terminate + , [&](int ticks, lt::session&) -> bool + { + if(tick_is_in_active_range){ + // 1 second per tick + expected_active_duration++; + } + + switch(ticks) + { + case 0: + // torrent get ready for seeding on first tick, means time +1s + tick_is_in_active_range = true; + break; + case 7000: + // pause before 4 hours to get a become finish timestamp which + // will be clamped + handle.pause(); + // resume to get an become finish update + handle.resume(); + // pause to test timeshift in paused state + handle.pause(); + tick_is_in_active_range = false; + break; + case 70000: + // simulate at least 70000 seconds because timestamps are + // 16 bits counting seconds + ran_to_completion = true; + return true; + } + + // verify that the timers seem correct + if (tick_is_in_active_range && (ticks % 3600) == 0) + { + torrent_status st = handle.status(); + TEST_EQUAL(st.active_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.seeding_duration.count(), expected_active_duration.count()); + TEST_EQUAL(st.finished_duration.count(), expected_active_duration.count()); + // does not upload without peers + TEST_CHECK(st.last_upload == start_time); + // does not download in seeding mode + TEST_CHECK(st.last_download == start_time); } return false; }); diff --git a/src/torrent.cpp b/src/torrent.cpp index 1acac85c2..52f4c942b 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -102,6 +102,9 @@ POSSIBILITY OF SUCH DAMAGE. #endif using namespace std::placeholders; +using std::chrono::duration_cast; +using std::chrono::seconds; +using libtorrent::seconds32; namespace libtorrent { @@ -121,7 +124,6 @@ namespace libtorrent } return ret; } - constexpr int default_piece_priority = 4; } // anonymous namespace @@ -180,8 +182,8 @@ namespace libtorrent , m_storage_constructor(p.storage) , m_added_time(time(nullptr)) , m_info_hash(info_hash) - , m_last_saved_resume(ses.session_time()) - , m_started(ses.session_time()) + , m_last_saved_resume(aux::time_now()) + , m_started(aux::time_now()) , m_error_file(torrent_status::error_file_none) , m_sequence_number(seq) , m_announce_to_trackers((p.flags & add_torrent_params::flag_paused) == 0) @@ -373,9 +375,9 @@ namespace libtorrent // the number of seconds this torrent has spent in started, finished and // seeding state so far, respectively. - m_active_time = p.active_time; - m_finished_time = p.finished_time; - m_seeding_time = p.seeding_time; + m_active_time = seconds(p.active_time); + m_finished_time = seconds(p.finished_time); + m_seeding_time = seconds(p.seeding_time); m_added_time = p.added_time ? p.added_time : time(nullptr); m_completed_time = p.completed_time; @@ -961,7 +963,7 @@ namespace libtorrent p->cancel_all_requests(); } // this is used to try leaving upload only mode periodically - m_upload_mode_time = m_ses.session_time(); + m_upload_mode_time = aux::time_now(); } else if (m_peer_list) { @@ -3849,7 +3851,7 @@ namespace libtorrent // is deallocated by the torrent once it starts seeding } - m_last_download = m_ses.session_time(); + m_last_download = aux::time_now(); if (m_share_mode) recalc_share_mode(); @@ -5950,9 +5952,10 @@ namespace libtorrent ret["total_uploaded"] = m_total_uploaded; ret["total_downloaded"] = m_total_downloaded; - ret["active_time"] = active_time(); - ret["finished_time"] = finished_time(); - ret["seeding_time"] = seeding_time(); + // cast to seconds in case that internal values doesn't have ratio<1> + ret["active_time"] = duration_cast(active_time()).count(); + ret["finished_time"] = duration_cast(finished_time()).count(); + ret["seeding_time"] = duration_cast(seeding_time()).count(); ret["last_seen_complete"] = m_last_seen_complete; ret["num_complete"] = m_complete; @@ -7241,7 +7244,7 @@ namespace libtorrent set_state(torrent_status::finished); set_queue_position(-1); - m_became_finished = m_ses.session_time(); + m_became_finished = aux::time_now(); // we have to call completed() before we start // disconnecting peers, since there's an assert @@ -7358,7 +7361,7 @@ namespace libtorrent maybe_done_flushing(); set_state(torrent_status::seeding); - m_became_seed = m_ses.session_time(); + m_became_seed = aux::time_now(); if (!m_announcing) return; @@ -8220,14 +8223,14 @@ namespace libtorrent if (a < b) return 0; return std::uint16_t(a - b); } - +#ifndef TORRENT_NO_DEPRECATE std::int16_t clamped_subtract_s16(int a, int b) { if (a + (std::numeric_limits::min)() < b) return (std::numeric_limits::min)(); return std::int16_t(a - b); } - +#endif } // anonymous namespace // this is called every time the session timer takes a step back. Since the @@ -8249,44 +8252,9 @@ namespace libtorrent } } - // m_active_time, m_seeding_time and m_finished_time are absolute counters - // of the historical time we've spent in each state. The current time - // we've spent in those states (this session) is calculated by - // session_time() - m_started - // session_time() - m_became_seed - // session_time() - m_became_finished respectively. If any of the - // comparison points were pulled back to the oldest representable value (0) - // the left-over time must be transferred into the m_*_time counters. - - if (m_started < seconds && !is_paused()) - { - int const lost_seconds = seconds - m_started; - m_active_time += lost_seconds; - } - m_started = clamped_subtract_u16(m_started, seconds); - - if (m_became_seed < seconds && is_seed()) - { - int const lost_seconds = seconds - m_became_seed; - m_seeding_time += lost_seconds; - } - m_became_seed = clamped_subtract_u16(m_became_seed, seconds); - - if (m_became_finished < seconds && is_finished()) - { - int const lost_seconds = seconds - m_became_finished; - m_finished_time += lost_seconds; - } - m_became_finished = clamped_subtract_u16(m_became_finished, seconds); - - m_last_upload = clamped_subtract_s16(m_last_upload, seconds); - m_last_download = clamped_subtract_s16(m_last_download, seconds); #ifndef TORRENT_NO_DEPRECATE m_last_scrape = clamped_subtract_s16(m_last_scrape, seconds); #endif - - m_last_saved_resume = clamped_subtract_u16(m_last_saved_resume, seconds); - m_upload_mode_time = clamped_subtract_u16(m_upload_mode_time, seconds); } // the higher seed rank, the more important to seed @@ -8308,15 +8276,16 @@ namespace libtorrent int ret = 0; - std::int64_t const fin_time = finished_time(); - std::int64_t const download_time = int(active_time()) - fin_time; + seconds32 const act_time = active_time(); + seconds32 const fin_time = finished_time(); + seconds32 const download_time = act_time - fin_time; // if we haven't yet met the seed limits, set the seed_ratio_not_met // flag. That will make this seed prioritized // downloaded may be 0 if the torrent is 0-sized std::int64_t const downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size()); - if (fin_time < s.get_int(settings_pack::seed_time_limit) - && (download_time > 1 + if (fin_time < seconds(s.get_int(settings_pack::seed_time_limit)) + && (download_time.count() > 1 && fin_time * 100 / download_time < s.get_int(settings_pack::seed_time_ratio_limit)) && downloaded > 0 && m_total_uploaded * 100 / downloaded < s.get_int(settings_pack::share_ratio_limit)) @@ -8324,7 +8293,7 @@ namespace libtorrent // if this torrent is running, and it was started less // than 30 minutes ago, give it priority, to avoid oscillation - if (!is_paused() && (m_ses.session_time() - m_started) < 30 * 60) + if (!is_paused() && act_time < minutes(30)) ret |= recently_started; // if we have any scrape data, use it to calculate @@ -8375,7 +8344,7 @@ namespace libtorrent } m_need_save_resume_data = false; - m_last_saved_resume = m_ses.session_time(); + m_last_saved_resume = aux::time_now(); m_save_resume_flags = std::uint8_t(flags); state_updated(); @@ -8472,13 +8441,16 @@ namespace libtorrent update_state_list(); update_want_tick(); - m_active_time += m_ses.session_time() - m_started; + const time_point now = aux::time_now(); - if (is_seed()) - m_seeding_time += m_ses.session_time() - m_became_seed; + m_active_time += + duration_cast(now - m_started); - if (is_finished()) - m_finished_time += m_ses.session_time() - m_became_finished; + if (is_seed()) m_seeding_time += + duration_cast(now - m_became_seed); + + if (is_finished()) m_finished_time += + duration_cast(now - m_became_finished); m_announce_to_dht = false; m_announce_to_trackers = false; @@ -8704,7 +8676,7 @@ namespace libtorrent if (alerts().should_post()) alerts().emplace_alert(get_handle()); - m_started = m_ses.session_time(); + m_started = aux::time_now(); if (is_seed()) m_became_seed = m_started; if (is_finished()) m_became_finished = m_started; @@ -8893,31 +8865,45 @@ namespace libtorrent announce_with_tracker(tracker_request::stopped); } - int torrent::finished_time() const + seconds32 torrent::finished_time() const { - // m_finished_time does not account for the current "session", just the - // time before we last started this torrent. To get the current time, we - // need to add the time since we started it - return m_finished_time + ((!is_finished() || is_paused()) ? 0 - : (m_ses.session_time() - m_became_finished)); + if(!is_finished() || is_paused()) + return m_finished_time; + + return m_finished_time + duration_cast( + aux::time_now() - m_became_finished); } - int torrent::active_time() const + seconds32 torrent::active_time() const { + if(is_paused()) + return m_active_time; + // m_active_time does not account for the current "session", just the // time before we last started this torrent. To get the current time, we // need to add the time since we started it - return m_active_time + (is_paused() ? 0 - : m_ses.session_time() - m_started); + return m_active_time + duration_cast( + aux::time_now() - m_started); } - int torrent::seeding_time() const + seconds32 torrent::seeding_time() const { + if(!is_seed() || is_paused()) + return m_seeding_time; // m_seeding_time does not account for the current "session", just the // time before we last started this torrent. To get the current time, we // need to add the time since we started it - return m_seeding_time + ((!is_seed() || is_paused()) ? 0 - : m_ses.session_time() - m_became_seed); + return m_seeding_time + duration_cast( + aux::time_now() - m_became_seed); + } + + seconds32 torrent::upload_mode_time() const + { + if(!m_upload_mode) + return seconds32(0); + + return duration_cast( + aux::time_now() - m_upload_mode_time); } void torrent::second_tick(int tick_interval_ms) @@ -8940,9 +8926,8 @@ namespace libtorrent // if we're in upload only mode and we're auto-managed // leave upload mode every 10 minutes hoping that the error // condition has been fixed - if (m_upload_mode && m_auto_managed - && int(m_ses.session_time() - m_upload_mode_time) - >= settings().get_int(settings_pack::optimistic_disk_retry)) + if (m_upload_mode && m_auto_managed && upload_mode_time() >= + seconds(settings().get_int(settings_pack::optimistic_disk_retry))) { set_upload_mode(false); } @@ -10580,22 +10565,23 @@ namespace libtorrent // activity time #ifndef TORRENT_NO_DEPRECATE - st->finished_time = finished_time(); - st->active_time = active_time(); - st->seeding_time = seeding_time(); + // cast to seconds in case that internal values doesn't have ratio<1> + st->finished_time = int(duration_cast(finished_time()).count()); + st->active_time = int(duration_cast(active_time()).count()); + st->seeding_time = int(duration_cast(seeding_time()).count()); - st->time_since_upload = m_last_upload == (std::numeric_limits::min)() ? -1 - : clamped_subtract_u16(m_ses.session_time(), m_last_upload); - st->time_since_download = m_last_download == (std::numeric_limits::min)() ? -1 - : clamped_subtract_u16(m_ses.session_time(), m_last_download); + st->time_since_upload = int(total_seconds(aux::time_now() + - m_last_upload)); + st->time_since_download = int(total_seconds(aux::time_now() + - m_last_download)); #endif - st->finished_duration = seconds{finished_time()}; - st->active_duration = seconds{active_time()}; - st->seeding_duration = seconds{seeding_time()}; + st->finished_duration = finished_time(); + st->active_duration = active_time(); + st->seeding_duration = seeding_time(); - st->last_upload = m_ses.session_start_time() + seconds(m_last_upload); - st->last_download = m_ses.session_start_time() + seconds(m_last_download); + st->last_upload = m_last_upload; + st->last_download = m_last_download; st->storage_mode = static_cast(m_storage_mode);