From 02ddb7ad1d09dee021cdd6e02dc331d41a45b7df Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 25 Feb 2016 00:27:26 -0500 Subject: [PATCH 01/29] add links to go, java and nodejs bindings and various cleanup to index.html. add paypal button --- docs/index.rst | 54 ++++++++++++++++++++++++++++++++++++++------------ docs/rst.css | 4 ++-- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 3543475f4..cb816b59d 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -10,7 +10,7 @@ * tutorial_ * examples_ * overview_ -* `reference documentation`_ +* documentation_ * contributing_ * building_ * troubleshooting_ @@ -41,8 +41,10 @@ Extensions Bindings -* `ruby bindings`_ -* `python bindings`_ +* python_ +* java_ +* go_ +* node_ -------- @@ -64,7 +66,7 @@ libtorrent .. _building: building.html .. _examples: examples.html .. _overview: manual-ref.html -.. _`reference documentation`: reference.html +.. _documentation: reference.html .. _troubleshooting: troubleshooting.html .. _`tuning`: tuning.html .. _screenshot: client_test.png @@ -85,8 +87,10 @@ libtorrent .. _`github page`: https://github.com/arvidn/libtorrent .. _blog: http://blog.libtorrent.org -.. _`ruby bindings`: http://libtorrent-ruby.rubyforge.org/ -.. _`python bindings`: python_binding.html +.. _java: https://github.com/frostwire/frostwire-jlibtorrent/ +.. _python: python_binding.html +.. _go: https://github.com/steeve/libtorrent-go +.. _node: https://github.com/fanatid/node-libtorrent .. _`Introduction, slides`: bittorrent.pdf @@ -104,22 +108,46 @@ The main goals of libtorrent are: * to be memory efficient * to be very easy to use -Donate -====== +Getting started +=============== -Support the development of libtorrent +The tutorial_ is an introduction to using libtorrent (C++). Also see the +`reference documentation`_. + +.. _`reference documentation`: reference.html + +Contribute +========== + +If your organization use libtorrent, please consider supporting its development. +See the contribute_ page for other ways to help out. .. raw:: html - + + + + + +
+ + + + + + + + +
+
-Feedback -======== +Support +======= -There's a `mailing list`__, general libtorrent discussion. +Please direct questions to the `mailing list`__, general libtorrent discussion. __ http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss diff --git a/docs/rst.css b/docs/rst.css index 6f523d942..c2d7875d6 100644 --- a/docs/rst.css +++ b/docs/rst.css @@ -223,13 +223,13 @@ div.contents { #librarySidebar { float: left; - width: 150px; + width: 170px; } #libraryBody { border-left: solid 1px #eee; padding-left: 10px; - margin-left: 158px; + margin-left: 178px; margin-right: 10px; } From b52027a02a0ae19617a57b82de0d62f69d2d406b Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Fri, 26 Feb 2016 19:16:17 -0800 Subject: [PATCH 02/29] set enable_dht to true in session::start_dht(entry) This function needs to enable the dht to match its semantics in pre 1.1 versions --- include/libtorrent/aux_/session_impl.hpp | 1 + src/session_handle.cpp | 2 +- src/session_impl.cpp | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index a5f066498..c155301fb 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -327,6 +327,7 @@ namespace libtorrent #ifndef TORRENT_NO_DEPRECATE entry dht_state() const; + void start_dht_deprecated(entry const& startup_state); #endif void on_dht_announce(error_code const& e); void on_dht_name_lookup(error_code const& e diff --git a/src/session_handle.cpp b/src/session_handle.cpp index 6e160f4df..cf359759b 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -468,7 +468,7 @@ namespace libtorrent void session_handle::start_dht(entry const& startup_state) { #ifndef TORRENT_DISABLE_DHT - TORRENT_ASYNC_CALL1(start_dht, startup_state); + TORRENT_ASYNC_CALL1(start_dht_deprecated, startup_state); #else TORRENT_UNUSED(startup_state); #endif diff --git a/src/session_impl.cpp b/src/session_impl.cpp index dc695b902..dc87c438a 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -5704,6 +5704,12 @@ retry: if (!m_dht) return entry(); return m_dht->state(); } + + void session_impl::start_dht_deprecated(entry const& startup_state) + { + m_settings.set_bool(settings_pack::enable_dht, true); + start_dht(startup_state); + } #endif void session_impl::add_dht_node_name(std::pair const& node) From 07ecf7c1bde476eabe7d1221299cae0579f4cb6d Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 00:25:21 -0500 Subject: [PATCH 03/29] remove invalid assert --- src/piece_picker.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 4cfd34796..02f4d101f 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -2823,8 +2823,6 @@ get_out: if (num_blocks <= 0) return 0; } - TORRENT_ASSERT(num_blocks >= 0 || prefer_contiguous_blocks > 0); - if (num_blocks <= 0) return 0; if (options & on_parole) return num_blocks; From ac2916c426c199cd9ec3fdb9606132e8e65348ed Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 17:41:18 -0500 Subject: [PATCH 04/29] enable disk cache pool allocator by default. fix ansi escape code conversion in client_test on windows --- examples/print.cpp | 71 +++++++++++++++++++++++++++++---------- examples/session_view.cpp | 4 +++ src/settings_pack.cpp | 2 +- 3 files changed, 59 insertions(+), 18 deletions(-) diff --git a/examples/print.cpp b/examples/print.cpp index ce94d6697..44639cf05 100644 --- a/examples/print.cpp +++ b/examples/print.cpp @@ -108,14 +108,21 @@ std::string const& progress_bar(int progress, int width, color_code c caption.resize(size_t(width), ' '); +#ifdef _WIN32 + char const* background = "40"; +#else + char const* background = "48;5;238"; +#endif + char str[256]; if (flags & progress_invert) - snprintf(str, sizeof(str), "\x1b[48;5;238m\x1b[37m%s\x1b[4%d;3%dm%s\x1b[49;39m" - , caption.substr(0, progress_chars).c_str(), c, tc + snprintf(str, sizeof(str), "\x1b[%sm\x1b[37m%s\x1b[4%d;3%dm%s\x1b[49;39m" + , background, caption.substr(0, progress_chars).c_str(), c, tc , caption.substr(progress_chars).c_str()); else - snprintf(str, sizeof(str), "\x1b[4%d;3%dm%s\x1b[48;5;238m\x1b[37m%s\x1b[49;39m" - , c, tc, caption.substr(0, progress_chars).c_str(), caption.substr(progress_chars).c_str()); + snprintf(str, sizeof(str), "\x1b[4%d;3%dm%s\x1b[%sm\x1b[37m%s\x1b[49;39m" + , c, tc, caption.substr(0, progress_chars).c_str(), background + , caption.substr(progress_chars).c_str()); bar = str; } return bar; @@ -208,7 +215,7 @@ void terminal_size(int* terminal_width, int* terminal_height) } #ifdef _WIN32 -void apply_ansi_code(int* attributes, bool* reverse, int code) +void apply_ansi_code(int* attributes, bool* reverse, bool* support_chaining, int code) { static const int color_table[8] = { @@ -224,8 +231,8 @@ void apply_ansi_code(int* attributes, bool* reverse, int code) enum { - foreground_mask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, - background_mask = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE + foreground_mask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY, + background_mask = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY }; static const int fg_mask[2] = {foreground_mask, background_mask}; @@ -233,14 +240,29 @@ void apply_ansi_code(int* attributes, bool* reverse, int code) static const int fg_shift[2] = { 0, 4}; static const int bg_shift[2] = { 4, 0}; + // default foreground + if (code == 39) code = 37; + + // default background + if (code == 49) code = 40; + if (code == 0) { // reset *attributes = color_table[7]; *reverse = false; + *support_chaining = true; + } + else if (code == 1) + { + // intensity + *attributes |= *reverse ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + *support_chaining = true; } else if (code == 7) { + // reverse video + *support_chaining = true; if (*reverse) return; *reverse = true; int fg_col = *attributes & foreground_mask; @@ -254,12 +276,14 @@ void apply_ansi_code(int* attributes, bool* reverse, int code) // foreground color *attributes &= ~fg_mask[*reverse]; *attributes |= color_table[code - 30] << fg_shift[*reverse]; + *support_chaining = true; } else if (code >= 40 && code <= 47) { - // foreground color + // background color *attributes &= ~bg_mask[*reverse]; *attributes |= color_table[code - 40] << bg_shift[*reverse]; + *support_chaining = true; } } #endif @@ -288,14 +312,15 @@ void print(char const* buf) CONSOLE_SCREEN_BUFFER_INFO sbi; if (GetConsoleScreenBufferInfo(out, &sbi)) { - COORD pos = sbi.dwCursorPosition; - int width = sbi.dwSize.X; - int run = width - pos.X; + COORD const pos = sbi.dwCursorPosition; + int const width = sbi.dwSize.X; + int const run = width - pos.X; DWORD n; FillConsoleOutputAttribute(out, 0x7, run, pos, &n); FillConsoleOutputCharacter(out, ' ', run, pos, &n); } ++buf; + start = buf; continue; } else if (*start == 'J') @@ -312,18 +337,30 @@ void print(char const* buf) FillConsoleOutputCharacter(out, ' ', run, pos, &n); } ++buf; + start = buf; continue; } - one_more: +one_more: while (*buf != 'm' && *buf != ';' && *buf != 0) ++buf; + + // this is where we handle reset, color and reverse codes if (*buf == 0) break; int code = atoi(start); - apply_ansi_code(¤t_attributes, &reverse, code); - if (*buf == ';') + bool support_chaining = false; + apply_ansi_code(¤t_attributes, &reverse, &support_chaining, code); + if (support_chaining) { - ++buf; - start = buf; - goto one_more; + if (*buf == ';') + { + ++buf; + start = buf; + goto one_more; + } + } + else + { + // ignore codes with multiple fields for now + while (*buf != 'm' && *buf != 0) ++buf; } SetConsoleTextAttribute(out, current_attributes); ++buf; // skip 'm' diff --git a/examples/session_view.cpp b/examples/session_view.cpp index 39e32d476..a2011d2b4 100644 --- a/examples/session_view.cpp +++ b/examples/session_view.cpp @@ -96,7 +96,11 @@ void session_view::render() snprintf(str, sizeof(str), "%s%swaste: %s up: %s (%s) " "disk queue: %s | %s cache w: %3d%% r: %3d%% " "size: w: %s r: %s total: %s %s\x1b[K" +#ifdef _WIN32 + , esc("40") +#else , esc("48;5;238") +#endif , esc("1") , add_suffix(m_cnt[0][m_wasted_bytes_idx]).c_str() , color(add_suffix(upload_rate, "/s"), col_red).c_str() diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index 9d34fa9f6..5f2779bb4 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -200,7 +200,7 @@ namespace libtorrent SET(support_merkle_torrents, true, 0), SET(report_redundant_bytes, true, 0), SET_NOPREV(listen_system_port_fallback, true, 0), - SET(use_disk_cache_pool, false, 0), + SET(use_disk_cache_pool, true, 0), SET_NOPREV(announce_crypto_support, true, 0), SET_NOPREV(enable_upnp, true, &session_impl::update_upnp), SET_NOPREV(enable_natpmp, true, &session_impl::update_natpmp), From 296a38efbaecadfe2c51b594c8e12eea2102ac83 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 19:40:04 -0500 Subject: [PATCH 05/29] improve windows output of client_test --- examples/client_test.cpp | 18 +++++++++++++----- examples/print.cpp | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index c376b7e4f..87fcb83cf 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -376,9 +376,13 @@ FILE* g_log_file = 0; std::string const& piece_bar(libtorrent::bitfield const& p, int width) { - const int table_size = 18; +#ifdef _WIN32 + int const table_size = 2; +#else + int const table_size = 18; +#endif - double piece_per_char = p.size() / double(width); + double const piece_per_char = p.size() / double(width); static std::string bar; bar.clear(); bar.reserve(width * 6); @@ -400,9 +404,13 @@ std::string const& piece_bar(libtorrent::bitfield const& p, int width) for (int k = int(piece); k < end; ++k, ++num_pieces) if (p[k]) ++num_have; int color = int(std::ceil(num_have / float((std::max)(num_pieces, 1)) * (table_size - 1))); - char buf[10]; - snprintf(buf, 10, "48;5;%d", 232 + color); - bar += esc(buf); + char buf[40]; +#ifdef _WIN32 + snprintf(buf, sizeof(buf), "\x1b[4%dm", color ? 7 : 0); +#else + snprintf(buf, sizeof(buf), "\x1b[48;5;%dm", 232 + color); +#endif + bar += buf; bar += " "; } bar += esc("0"); diff --git a/examples/print.cpp b/examples/print.cpp index 44639cf05..83f888c77 100644 --- a/examples/print.cpp +++ b/examples/print.cpp @@ -88,7 +88,7 @@ std::string const& progress_bar(int progress, int width, color_code c bar.clear(); bar.reserve(size_t(width + 10)); - int progress_chars = (progress * width + 500) / 1000; + int const progress_chars = (progress * width + 500) / 1000; if (caption.empty()) { From f563bf9cace0bdb1dcf7d174f28e64f3662656e6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 20:25:17 -0500 Subject: [PATCH 06/29] attempt to make the alert type backwards compatible with cloning the state when building with deprecated functions enabled --- include/libtorrent/alert.hpp | 28 ++++++------------- src/alert.cpp | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/include/libtorrent/alert.hpp b/include/libtorrent/alert.hpp index 08751de51..76bea9b99 100644 --- a/include/libtorrent/alert.hpp +++ b/include/libtorrent/alert.hpp @@ -77,22 +77,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/time.hpp" #include "libtorrent/config.hpp" -#ifndef TORRENT_NO_DEPRECATE -#ifndef BOOST_NO_TYPEID -#include -#endif -#endif // TORRENT_NO_DEPRECATE - -#ifndef TORRENT_MAX_ALERT_TYPES -#define TORRENT_MAX_ALERT_TYPES 15 -#endif - -#ifndef TORRENT_NO_DEPRECATE -#ifndef BOOST_NO_TYPEID -#include -#endif -#endif - namespace libtorrent { // The ``alert`` class is the base class that specific messages are derived from. @@ -216,9 +200,6 @@ namespace libtorrent { alert(); // hidden virtual ~alert(); -#if __cplusplus >= 201103L - alert(alert const&) = default; -#endif // a timestamp is automatically created in the constructor time_point timestamp() const; @@ -301,8 +282,15 @@ namespace libtorrent { #endif // TORRENT_NO_DEPRECATE + protected: +#if __cplusplus >= 201103L + alert(alert const&) = default; +#else + alert(alert const&); +#endif + private: - // explicitly disallow assignment, to silence msvc warning + // explicitly disallow assignment and copyconstruction alert& operator=(alert const&); time_point m_timestamp; diff --git a/src/alert.cpp b/src/alert.cpp index 670454fe8..79a965681 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -87,7 +87,11 @@ namespace libtorrent { char const* torrent_alert::torrent_name() const { +#ifndef TORRENT_NO_DEPRECATE + return name.c_str(); +#else return m_alloc.ptr(m_name_idx); +#endif } std::string torrent_alert::message() const @@ -124,7 +128,11 @@ namespace libtorrent { char const* tracker_alert::tracker_url() const { +#ifndef TORRENT_NO_DEPRECATE + return url.c_str(); +#else return m_alloc.ptr(m_url_idx); +#endif } std::string tracker_alert::message() const @@ -195,7 +203,11 @@ namespace libtorrent { char const* file_renamed_alert::new_name() const { +#ifndef TORRENT_NO_DEPRECATE + return name.c_str(); +#else return m_alloc.ptr(m_name_idx); +#endif } std::string file_renamed_alert::message() const @@ -292,7 +304,11 @@ namespace libtorrent { char const* tracker_error_alert::error_message() const { +#ifndef TORRENT_NO_DEPRECATE + return msg.c_str(); +#else return m_alloc.ptr(m_msg_idx); +#endif } std::string tracker_error_alert::message() const @@ -320,7 +336,11 @@ namespace libtorrent { char const* tracker_warning_alert::warning_message() const { +#ifndef TORRENT_NO_DEPRECATE + return msg.c_str(); +#else return m_alloc.ptr(m_msg_idx); +#endif } std::string tracker_warning_alert::message() const @@ -378,8 +398,12 @@ namespace libtorrent { char const* scrape_failed_alert::error_message() const { +#ifndef TORRENT_NO_DEPRECATE + return msg.c_str(); +#else if (m_msg_idx == -1) return ""; else return m_alloc.ptr(m_msg_idx); +#endif } std::string scrape_failed_alert::message() const @@ -649,7 +673,11 @@ namespace libtorrent { char const* storage_moved_alert::storage_path() const { +#ifndef TORRENT_NO_DEPRECATE + return path.c_str(); +#else return m_alloc.ptr(m_path_idx); +#endif } storage_moved_failed_alert::storage_moved_failed_alert( @@ -669,7 +697,11 @@ namespace libtorrent { char const* storage_moved_failed_alert::file_path() const { +#ifndef TORRENT_NO_DEPRECATE + return file.c_str(); +#else return m_alloc.ptr(m_file_idx); +#endif } std::string storage_moved_failed_alert::message() const @@ -939,7 +971,11 @@ namespace libtorrent { char const* portmap_log_alert::log_message() const { +#ifndef TORRENT_NO_DEPRECATE + return msg.c_str(); +#else return m_alloc.ptr(m_log_idx); +#endif } std::string portmap_log_alert::message() const @@ -980,7 +1016,11 @@ namespace libtorrent { char const* fastresume_rejected_alert::file_path() const { +#ifndef TORRENT_NO_DEPRECATE + return file.c_str(); +#else return m_alloc.ptr(m_path_idx); +#endif } peer_blocked_alert::peer_blocked_alert(aux::stack_allocator& alloc @@ -1145,7 +1185,11 @@ namespace libtorrent { char const* trackerid_alert::tracker_id() const { +#ifndef TORRENT_NO_DEPRECATE + return trackerid.c_str(); +#else return m_alloc.ptr(m_tracker_idx); +#endif } std::string trackerid_alert::message() const @@ -1710,8 +1754,12 @@ namespace libtorrent { char const* url_seed_alert::error_message() const { +#ifndef TORRENT_NO_DEPRECATE + return msg.c_str(); +#else if (m_msg_idx == -1) return ""; return m_alloc.ptr(m_msg_idx); +#endif } file_error_alert::file_error_alert(aux::stack_allocator& alloc @@ -1734,7 +1782,11 @@ namespace libtorrent { char const* file_error_alert::filename() const { +#ifndef TORRENT_NO_DEPRECATE + return file.c_str(); +#else return m_alloc.ptr(m_file_idx); +#endif } std::string file_error_alert::message() const From 12dce2ccdb902efcb963bd2241d93adca5754ba6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 10:32:13 -0500 Subject: [PATCH 07/29] forward port python binding test for torrent_status::save_path --- bindings/python/test.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bindings/python/test.py b/bindings/python/test.py index 20988b9b4..324b8cb46 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -31,7 +31,8 @@ class test_alerts(unittest.TestCase): ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) shutil.copy(os.path.join('..', '..', 'test', 'test_torrents', 'base.torrent'), '.') ti = lt.torrent_info('base.torrent'); - h = ses.add_torrent({'ti': ti, 'save_path': '.'}) + h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) + st = h.status() time.sleep(1) ses.remove_torrent(h) ses.wait_for_alert(1000) # milliseconds @@ -39,9 +40,8 @@ class test_alerts(unittest.TestCase): for a in alerts: print(a.message()) - st = h.status() print(st.next_announce) - print(st.name) + self.assertEqual(st.name, 'temp') print(st.errc.message()) print(st.pieces) print(st.last_seen_complete) @@ -51,6 +51,7 @@ class test_alerts(unittest.TestCase): print(st.distributed_copies) print(st.paused) print(st.info_hash) + self.assertEqual(st.save_path, os.getcwd()) class test_bencoder(unittest.TestCase): From 2f745a181cfac98a7f756a20f3f35a0e08378f07 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 27 Feb 2016 23:53:25 -0500 Subject: [PATCH 08/29] fix typo and make alert non-copyable --- include/libtorrent/alert.hpp | 9 ++++++--- include/libtorrent/alert_types.hpp | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/libtorrent/alert.hpp b/include/libtorrent/alert.hpp index 76bea9b99..2bcb3661b 100644 --- a/include/libtorrent/alert.hpp +++ b/include/libtorrent/alert.hpp @@ -80,6 +80,9 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { // The ``alert`` class is the base class that specific messages are derived from. + // alert types are not copyable, and cannot be constructed by the client. The + // pointers returned by libtorrent are short lived (the details are described + // under session_handle::pop_alerts()) class TORRENT_EXPORT alert { public: @@ -283,10 +286,10 @@ namespace libtorrent { #endif // TORRENT_NO_DEPRECATE protected: + // the alert is not copyable (but for backwards compatibility reasons it + // retains the ability to clone itself, for now). #if __cplusplus >= 201103L - alert(alert const&) = default; -#else - alert(alert const&); + alert(alert const& rhs) = default; #endif private: diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 927333590..6889500f3 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -163,7 +163,25 @@ namespace libtorrent #define TORRENT_CLONE(name) #endif + // we can only use = default in C++11 + // the purpose of this is just to make all alert types non-copyable from user + // code. The heterogeneous queue does not yet have an emplace_back(), so it + // still needs to copy alerts, but the important part is that it's not + // copyable for clients. + // TODO: Once the backwards compatibility of clone() is removed, and once + // C++11 is required, this can be simplified to just say = delete +#if __cplusplus >= 201103L + #define TORRENT_PROTECTED_CCTOR(name) \ + protected: \ + template friend struct heterogeneous_queue; \ + name(name const&) = default; \ + public: +#else + #define TORRENT_PROTECTED_CCTOR(name) +#endif + #define TORRENT_DEFINE_ALERT_IMPL(name, seq, prio) \ + TORRENT_PROTECTED_CCTOR(name) \ static const int priority = prio; \ static const int alert_type = seq; \ virtual int type() const TORRENT_OVERRIDE { return alert_type; } \ From 8ffa76842cf2b61f4c81cfbebe819d5d7d157e6a Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 28 Feb 2016 01:18:27 -0500 Subject: [PATCH 09/29] fix test_upnp build --- include/libtorrent/upnp.hpp | 1 + test/Jamfile | 4 ++-- test/test_upnp.cpp | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index 2421b9cd1..691d27515 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -98,6 +98,7 @@ namespace libtorrent // int: port-mapping index // address: external address as queried from router // int: external port +// int: protocol (UDP, TCP) // std::string: error message // an empty string as error means success typedef boost::function portmap_callback_t; diff --git a/test/Jamfile b/test/Jamfile index e96abf4f3..1281f4735 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -193,8 +193,8 @@ test-suite libtorrent : [ run test_priority.cpp ] # turn these tests into simulations -# [ run test_upnp.cpp ] -# [ run test_lsd.cpp ] + [ run test_upnp.cpp ] + [ run test_lsd.cpp ] ; # these are the tests run on appveyor, while the flapping ones are being diff --git a/test/test_upnp.cpp b/test/test_upnp.cpp index 6d0cb5f66..447bab5a8 100644 --- a/test/test_upnp.cpp +++ b/test/test_upnp.cpp @@ -119,12 +119,12 @@ struct callback_info std::list callbacks; -void callback(int mapping, address const& ip, int port, error_code const& err) +void callback(int mapping, address const& ip, int port, int protocol, error_code const& err) { callback_info info = {mapping, port, err}; callbacks.push_back(info); std::cerr << "mapping: " << mapping << ", port: " << port << ", IP: " << ip - << ", error: \"" << err.message() << "\"\n"; + << ", proto: " << protocol << ", error: \"" << err.message() << "\"\n"; } void run_upnp_test(char const* root_filename, char const* router_model, char const* control_name, int igd_version) From 021375c07fda29e37debba2e463c2c4ef0a386d5 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 28 Feb 2016 15:44:59 -0500 Subject: [PATCH 10/29] extend tutorial and finish bt-get example --- docs/tutorial.rst | 69 ++++++++++++++++++++++++++++++++++------ examples/bt-get2.cpp | 16 +++++++--- examples/client_test.cpp | 4 +-- 3 files changed, 72 insertions(+), 17 deletions(-) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 511e52281..eae609ac7 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -52,10 +52,10 @@ First, let's extend the example to print out messages from the bittorrent engine about progress and events happening under the hood. libtorrent has a mechanism referred to as *alerts* to communicate back information to the client application. -Clients can poll libtorrents for new alerts via the `pop_alerts()`_ call on the -session object. This call fills in a vector of alert pointers with all new -alerts since the last call to this function. The pointers are owned by the -session object at will become invalidated by the next call to `pop_alerts()`_. +Clients can poll a session for new alerts via the `pop_alerts()`_ call. This +function fills in a vector of alert pointers with all new alerts since the last +call to this function. The pointers are owned by the session object at will +become invalidated by the next call to `pop_alerts()`_. The alerts form a class hierarchy with alert_ as the root class. Each specific kind of alert may include additional state, specific to the kind of message. All @@ -183,10 +183,10 @@ resuming torrents Since bittorrent downloads pieces of files in random order, it's not trivial to resume a partial download. When resuming a download, the bittorrent engine must -restore the state of the downloading torrent, specifically, which parts of the +restore the state of the downloading torrent, specifically which parts of the file(s) are downloaded. There are two approaches to doing this: -1. read every piece of the downloaded files from disk and compare it against the +1. read every piece of the downloaded files from disk and compare it against its expected hash. 2. save to disk the state of which pieces (and partial pieces) are downloaded, and load it back in again when resuming. @@ -197,8 +197,14 @@ employ (1) by default. To save resume data, call `save_resume_data()`_ on the torrent_handle_ object. This will ask libtorrent to generate the resume data and post it back in a save_resume_data_alert_. If generating the resume data fails for any reason, -a save_resume_data_failed_alert_ is posted instead. Exactly one of those alerts -will be posted for every call to `save_resume_data()`_. +a save_resume_data_failed_alert_ is posted instead. + +Exactly one of those alerts will be posted for every call to +`save_resume_data()`_. This is an important property when shutting down a +session with multiple torrents, every resume alert must be handled before +resuming with shut down. Any torrent may fail to save resume data, so the client +would need to keep a count of the outstanding resume files, decremented on +either save_resume_data_alert_ or save_resume_data_failed_alert_. The save_resume_data_alert_ looks something like this: @@ -212,10 +218,13 @@ The save_resume_data_alert_ looks something like this: boost::shared_ptr resume_data; }; -``resume_data`` points to an entry_ object. This represents a node or a tree -of nodes in a bencoded_ structure, which is the native encoding scheme in +``resume_data`` points to an entry_ object. This represents a node or a tree of +nodes in a bencoded_ structure, which is the native encoding scheme in bittorrent. It can be encoded into a byte buffer or file using `bencode()`_. +When adding a torrent with resume data, set the `add_torrent_params::resume_data`_ +to contain the bencoded buffer of the resume data. + example ------- @@ -230,6 +239,41 @@ Here's an updated version of the above example with the following updates: :tab-width: 2 :start-after: */ +torrent files +------------- + +To add torrent files to a session (as opposed to a magnet link), it must first +be loaded into a torrent_info_ object. + +The torrent_info_ object can be created either by filename a buffer or a +bencoded structure. When adding by filename, there's a sanity check limit on the +size of the file, for adding arbitrarily large torrents, load the file outside +of the constructor. + +The torrent_info_ object provides an opportunity to query information about the +.torrent file as well as mutating it before adding it to the session. + +bencoding +--------- + +bencoded_ structures is the default data storage format used by bittorrent, such +as .torrent files, tracker announce and scrape responses and some wire protocol +extensions. libtorrent provides an efficient framework for decoding bencoded +data through `bdecode()`_ function. + +There are two separate mechanisms for *encoding* and *decoding*. When decoding, +use the `bdecode()`_ function that returns a bdecode_node_. When encoding, use +`bencode()`_ taking an entry_ object. + +The key property of `bdecode()`_ is that it does not copy any data out of the +buffer that was parsed. It builds the tree structures of references pointing +into the buffer. The buffer must stay alive and valid for as long as the +bdecode_node_ is in use. + +For performance details on `bdecode()`_, see the `blog post about it`__. + +__ http://blog.libtorrent.org/2015/03/bdecode-parsers/ + .. _session: reference-Core.html#session .. _session_handle: reference-Core.html#session_handle .. _add_torrent_params: reference-Core.html#add_torrent_params @@ -258,4 +302,9 @@ Here's an updated version of the above example with the following updates: .. _bencoded: https://en.wikipedia.org/wiki/Bencode .. _entry: reference-Bencoding.html#entry .. _`bencode()`: reference-Bencoding.html#bencode() +.. _torrent_info: reference-Core.html#torrent_info +.. _`add_torrent_params::resume_data`: reference-Core.html#resume_data +.. _`bdecode()`: reference-Bdecoding.html#bdecode() +.. _bdecode_node: reference-Bdecoding.html#bdecode-node + diff --git a/examples/bt-get2.cpp b/examples/bt-get2.cpp index ab0873747..f8db4db04 100644 --- a/examples/bt-get2.cpp +++ b/examples/bt-get2.cpp @@ -43,12 +43,12 @@ POSSIBILITY OF SUCH DAMAGE. #include namespace lt = libtorrent; +using clock_t = std::chrono::monotonic_clock; // return the name of a torrent status enum char const* state(lt::torrent_status::state_t s) { - switch(s) - { + switch(s) { case lt::torrent_status::checking_files: return "checking"; case lt::torrent_status::downloading_metadata: return "dl metadata"; case lt::torrent_status::downloading: return "downloading"; @@ -74,8 +74,8 @@ int main(int argc, char const* argv[]) | lt::alert::status_notification); lt::session ses(pack); - lt::add_torrent_params atp; + std::chrono::time_point last_save_resume = clock_t::now(); // load resume data from disk and pass it in as we add the magnet link std::ifstream ifs(".resume_file", std::ios_base::binary); @@ -134,9 +134,15 @@ int main(int argc, char const* argv[]) // state output for the torrent ses.post_torrent_updates(); - // TODO: 3 call save_resume_data() once every 30 seconds or so + // save resume data once every 30 seconds + if (clock_t::now() - last_save_resume > seconds(30)) { + h.save_resume_data(); + } } - done: + + // TODO: ideally we should save resume data here + +done: std::cout << "\ndone, shutting down" << std::endl; } diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 87fcb83cf..79e092155 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -2182,7 +2182,7 @@ int main(int argc, char* argv[]) std::vector file_progress; h.file_progress(file_progress); std::vector file_status; - h.file_status(file_status); + h.file_status(file_status); std::vector file_prio = h.file_priorities(); std::vector::iterator f = file_status.begin(); boost::shared_ptr ti = h.torrent_file(); @@ -2295,7 +2295,7 @@ int main(int argc, char* argv[]) ses.pause(); printf("saving resume data\n"); std::vector temp; - ses.get_torrent_status(&temp, &yes, 0); + ses.get_torrent_status(&temp, &yes, 0); for (std::vector::iterator i = temp.begin(); i != temp.end(); ++i) { From aeb9f1c5dd2a5ff2d0ebec720f0f2923d89acff2 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 29 Feb 2016 18:14:10 -0500 Subject: [PATCH 11/29] fix bug in enum_net_interfaces --- src/enum_net.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/enum_net.cpp b/src/enum_net.cpp index 01bf12341..9b0abab46 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -599,6 +599,7 @@ namespace libtorrent if (r == ERROR_BUFFER_OVERFLOW) { buffer.resize(buf_size); + adapter_addresses = reinterpret_cast(&buffer[0]); r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &buf_size); } From e851b7986583499e11c34aa0dd790c6b11d57f7e Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 2 Mar 2016 01:16:08 -0500 Subject: [PATCH 12/29] fix issue when shutting down a torrent with outstanding async operations --- src/session_impl.cpp | 4 ++-- src/torrent.cpp | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index dc87c438a..07c7270df 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -3438,7 +3438,7 @@ retry: 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 }; - v |= v >> 1; // first round down to one less than a power of 2 + v |= v >> 1; // first round down to one less than a power of 2 v |= v >> 2; v |= v >> 4; v |= v >> 8; @@ -5058,7 +5058,7 @@ retry: // we have specific outgoing interfaces specified. Make sure the // local endpoint for this socket is bound to one of the allowed // interfaces. the list can be a mixture of interfaces and IP - // addresses. first look for the address + // addresses. first look for the address for (int i = 0; i < int(m_net_interfaces.size()); ++i) { error_code err; diff --git a/src/torrent.cpp b/src/torrent.cpp index 0a016cce0..e51edbc66 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1258,6 +1258,8 @@ namespace libtorrent TORRENT_UNUSED(j); TORRENT_UNUSED(b); + if (m_abort) return; + update_gauge(); // some peers that previously was no longer interesting may // now have become interesting, since we lack this one piece now. @@ -2325,6 +2327,8 @@ namespace libtorrent return; } + if (m_abort) return; + state_updated(); if (m_resume_data && m_resume_data->node.type() == bdecode_node::dict_t) @@ -2647,6 +2651,8 @@ namespace libtorrent dec_refcount("force_recheck"); state_updated(); + if (m_abort) return; + if (j->ret == piece_manager::fatal_disk_error) { handle_disk_error(j); @@ -2727,6 +2733,8 @@ namespace libtorrent dec_refcount("start_checking"); + if (m_abort) return; + if (j->ret == piece_manager::disk_check_aborted) { m_checking_piece = 0; @@ -3041,6 +3049,7 @@ namespace libtorrent , int(peers.size())); #endif + if (m_abort) return; if (peers.empty()) return; if (m_ses.alerts().should_post()) @@ -3752,7 +3761,7 @@ namespace libtorrent if (ec) debug_log("i2p_resolve error: %s", ec.message().c_str()); #endif - if (ec || m_ses.is_aborted()) return; + if (ec || m_abort || m_ses.is_aborted()) return; need_peer_list(); torrent_state st = get_peer_list_state(); @@ -3778,7 +3787,7 @@ namespace libtorrent debug_log("peer name lookup error: %s", e.message().c_str()); #endif - if (e || host_list.empty() || m_ses.is_aborted()) return; + if (e || m_abort || host_list.empty() || m_ses.is_aborted()) return; // TODO: add one peer per IP the hostname resolves to tcp::endpoint host(host_list.front(), port); @@ -4124,6 +4133,8 @@ namespace libtorrent dec_refcount("verify_piece"); + if (m_abort) return; + int ret = j->ret; if (settings().get_bool(settings_pack::disable_hash_checks)) { @@ -10555,6 +10566,7 @@ namespace libtorrent update_want_peers(); } + // TODO: 2 this should probably be removed void torrent::refresh_explicit_cache(int cache_size) { TORRENT_ASSERT(is_single_thread()); From 84eafac1e201d757d94fc207b1554a45faecab1b Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 2 Mar 2016 21:35:08 -0500 Subject: [PATCH 13/29] add more slack to test_recheck, as it has been failing on and off on travis --- test/test_recheck.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test_recheck.cpp b/test/test_recheck.cpp index d35293d1b..4b290e7ee 100644 --- a/test/test_recheck.cpp +++ b/test/test_recheck.cpp @@ -55,12 +55,20 @@ const int mask = alert::all_categories & ~(alert::performance_warning | alert::s void wait_for_complete(lt::session& ses, torrent_handle h) { - for (int i = 0; i < 70; ++i) + int last_progress = 0; + clock_type::time_point last_change = clock_type::now(); + for (int i = 0; i < 400; ++i) { print_alerts(ses, "ses1"); torrent_status st = h.status(); fprintf(stderr, "%f %%\n", st.progress_ppm / 10000.f); if (st.progress_ppm == 1000000) return; + if (st.progress_ppm != last_progress) + { + last_progress = st.progress_ppm; + last_change = clock_type::now(); + } + if (clock_type::now() - last_change > seconds(10)) break; test_sleep(500); } TEST_ERROR("torrent did not finish"); @@ -107,3 +115,4 @@ TORRENT_TEST(recheck) TEST_CHECK(st1.progress_ppm <= 1000000); wait_for_complete(ses1, tor1); } + From fbef47d3ec7202c9cbfb158ec2f39e767dfe6df6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 2 Mar 2016 22:30:02 -0500 Subject: [PATCH 14/29] fix edge case in uTP stream when receiving a close-reason code --- src/utp_stream.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index f1311df1e..318bd8972 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -923,8 +923,11 @@ int utp_stream::read_buffer_size() const void utp_stream::on_close_reason(void* self, boost::uint16_t close_reason) { utp_stream* s = static_cast(self); - TORRENT_ASSERT(s->m_impl); - s->m_incoming_close_reason = close_reason; + + // it's possible the socket has been unlinked already, in which case m_impl + // will be NULL + if (s->m_impl) + s->m_incoming_close_reason = close_reason; } void utp_stream::on_read(void* self, size_t bytes_transferred From b9ec183e24c766a38dd02ca1f3438b470bc01469 Mon Sep 17 00:00:00 2001 From: arvidn Date: Tue, 1 Mar 2016 01:57:24 -0500 Subject: [PATCH 15/29] increase default connect speed. minor cleanup. add logging for short lived connections --- include/libtorrent/peer_connection.hpp | 2 +- src/bt_peer_connection.cpp | 6 +-- src/peer_connection.cpp | 52 +++++++++++++++++--------- src/settings_pack.cpp | 2 +- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 1bdfaed0c..05db4ecf2 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -589,7 +589,7 @@ namespace libtorrent bool can_disconnect(error_code const& ec) const; void incoming_dht_port(int listen_port); - + void incoming_reject_request(peer_request const& r); void incoming_have_all(); void incoming_have_none(); diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index a42631c50..729a37041 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -808,7 +808,7 @@ namespace libtorrent // we support FAST extension *(ptr + 7) |= 0x04; -#ifndef TORRENT_DISABLE_LOGGING +#ifndef TORRENT_DISABLE_LOGGING std::string bitmask; for (int k = 0; k < 8; ++k) { @@ -3285,7 +3285,7 @@ namespace libtorrent recv_buffer = m_recv_buffer.get(); -#ifndef TORRENT_DISABLE_LOGGING +#ifndef TORRENT_DISABLE_LOGGING std::string extensions; extensions.resize(8 * 8); for (int i=0; i < 8; ++i) @@ -3461,7 +3461,7 @@ namespace libtorrent #endif #ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::incoming_message, "HANDSHAKE"); + peer_log(peer_log_alert::incoming_message, "HANDSHAKE", "connection ready"); #endif // consider this a successful connection, reset the failcount if (peer_info_struct()) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index ac991159c..db8f14d79 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -803,7 +803,7 @@ namespace libtorrent m_connected = false; if (!m_download_queue.empty()) m_counters.inc_stats_counter(counters::num_peers_down_requests, -1); - + // defensive boost::shared_ptr t = m_torrent.lock(); // if t is NULL, we better not be connecting, since @@ -990,13 +990,13 @@ namespace libtorrent TORRENT_ASSERT(is_single_thread()); return m_request_queue; } - + std::vector const& peer_connection::download_queue() const { TORRENT_ASSERT(is_single_thread()); return m_download_queue; } - + std::vector const& peer_connection::upload_queue() const { TORRENT_ASSERT(is_single_thread()); @@ -1878,7 +1878,7 @@ namespace libtorrent m_have_piece.set_bit(index); ++m_num_pieces; - // if the peer is downloading stuff, it must have metadata + // if the peer is downloading stuff, it must have metadata m_has_metadata = true; // only update the piece_picker if @@ -2576,9 +2576,9 @@ namespace libtorrent { check_postcondition(boost::shared_ptr const& t_ , bool init_check = true): t(t_) { if (init_check) check(); } - + ~check_postcondition() { check(); } - + void check() { if (!t->is_seed()) @@ -2596,7 +2596,7 @@ namespace libtorrent } } } - + shared_ptr t; }; #endif @@ -3229,7 +3229,7 @@ namespace libtorrent disconnect_if_redundant(); } - + // ----------------------------- // --------- HAVE NONE --------- // ----------------------------- @@ -3495,8 +3495,8 @@ namespace libtorrent if (t->alerts().should_post()) { - t->alerts().emplace_alert(t->get_handle(), - remote(), pid(), block.block_index, block.piece_index); + t->alerts().emplace_alert(t->get_handle() + , remote(), pid(), block.block_index, block.piece_index); } pending_block pb(block); @@ -3643,6 +3643,8 @@ namespace libtorrent TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; + TORRENT_ASSERT(!is_connecting()); + if (m_choked) { TORRENT_ASSERT(m_peer_info == NULL @@ -4082,6 +4084,15 @@ namespace libtorrent , op, ec.message().c_str()); break; } + + if (ec == error_code(boost::asio::error::eof + , boost::asio::error::get_misc_category()) + && !in_handshake() + && !is_connecting() + && clock_type::now() - connected_time() < seconds(15)) + { + peer_log(peer_log_alert::info, "SHORT_LIVED_DISCONNECT", ""); + } #endif if ((m_channel_state[upload_channel] & peer_info::bw_network) == 0) @@ -4955,8 +4966,8 @@ namespace libtorrent boost::int64_t piece_size = t->torrent_file().piece_length(); if (m_remote_dl_rate > 0) - m_remote_dl_rate = int((m_remote_dl_rate * 2 / 3) + - ((boost::int64_t(m_remote_pieces_dled) * piece_size / 3) / 60)); + m_remote_dl_rate = int((m_remote_dl_rate * 2 / 3) + + ((boost::int64_t(m_remote_pieces_dled) * piece_size / 3) / 60)); else m_remote_dl_rate = int(boost::int64_t(m_remote_pieces_dled) * piece_size / 60); @@ -5355,7 +5366,7 @@ namespace libtorrent disconnect(j->error.ec, op_file_read); return; } - + if (j->ret != r.length) { // handle_disk_error may disconnect us @@ -5715,7 +5726,7 @@ namespace libtorrent { return; } - + if (!can_read()) { #ifndef TORRENT_DISABLE_LOGGING @@ -5980,8 +5991,11 @@ namespace libtorrent if (error) { + TORRENT_ASSERT_VAL(error.value() != 0, error.value()); #ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::info, "ERROR", "in peer_connection::on_receive_data_nb error: %s" + peer_log(peer_log_alert::info, "ERROR" + , "in peer_connection::on_receive_data_nb error: (%s:%d) %s" + , error.category().name(), error.value() , error.message().c_str()); #endif on_receive(error, bytes_transferred); @@ -6106,8 +6120,10 @@ namespace libtorrent { TORRENT_ASSERT(is_single_thread()); #ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::incoming, "ON_RECEIVE_DATA", "bytes: %d error: %s" - , int(bytes_transferred), error.message().c_str()); + peer_log(peer_log_alert::incoming, "ON_RECEIVE_DATA" + , "bytes: %d error: (%s:%d) %s" + , int(bytes_transferred), error.category().name(), error.value() + , error.message().c_str()); #endif // submit all disk jobs later @@ -6836,7 +6852,7 @@ namespace libtorrent time_duration d; d = aux::time_now() - m_last_sent; if (total_seconds(d) < timeout() / 2) return; - + if (m_connecting) return; if (in_handshake()) return; diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index 5f2779bb4..dbc979967 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -233,7 +233,7 @@ namespace libtorrent SET(max_failcount, 3, &session_impl::update_max_failcount), SET(min_reconnect_time, 60, 0), SET(peer_connect_timeout, 15, 0), - SET(connection_speed, 6, &session_impl::update_connection_speed), + SET(connection_speed, 10, &session_impl::update_connection_speed), SET(inactivity_timeout, 600, 0), SET(unchoke_interval, 15, 0), SET(optimistic_unchoke_interval, 30, 0), From 2e7e679eedb45b1ed7205d010bfb1b186a4b25c6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 2 Mar 2016 00:53:32 -0500 Subject: [PATCH 16/29] simplify client_test shutdown and make it keep logging as saving resume data --- examples/client_test.cpp | 39 ++++----------------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 79e092155..e9e719023 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -2287,11 +2287,6 @@ int main(int argc, char* argv[]) } } - // keep track of the number of resume data - // alerts to wait for - int num_paused = 0; - int num_failed = 0; - ses.pause(); printf("saving resume data\n"); std::vector temp; @@ -2334,38 +2329,12 @@ int main(int argc, char* argv[]) for (std::vector::iterator i = alerts.begin() , end(alerts.end()); i != end; ++i) { - torrent_paused_alert* tp = alert_cast(*i); - if (tp) + if (!::handle_alert(ses, *i, files, non_files)) { - ++num_paused; - printf("\rleft: %d failed: %d pause: %d " - , num_outstanding_resume_data, num_failed, num_paused); - continue; + // if we didn't handle the alert, print it to the log + std::string event_string; + print_alert(*i, event_string); } - - if (alert_cast(*i)) - { - ++num_failed; - --num_outstanding_resume_data; - printf("\rleft: %d failed: %d pause: %d " - , num_outstanding_resume_data, num_failed, num_paused); - continue; - } - - save_resume_data_alert* rd = alert_cast(*i); - if (!rd) continue; - --num_outstanding_resume_data; - printf("\rleft: %d failed: %d pause: %d " - , num_outstanding_resume_data, num_failed, num_paused); - - if (!rd->resume_data) continue; - - torrent_handle h = rd->handle; - torrent_status st = h.status(torrent_handle::query_save_path); - std::vector out; - bencode(std::back_inserter(out), *rd->resume_data); - save_file(path_append(st.save_path, path_append(".resume" - , leaf_path(hash_to_filename[st.info_hash]) + ".resume")), out); } } From 4998bfedc6fa66de4250d07018fd0ba1da3b872d Mon Sep 17 00:00:00 2001 From: Alden Torres Date: Fri, 19 Feb 2016 10:50:17 -0500 Subject: [PATCH 17/29] Documentation typos --- include/libtorrent/entry.hpp | 2 +- include/libtorrent/kademlia/msg.hpp | 2 +- include/libtorrent/operations.hpp | 2 +- src/kademlia/dht_storage.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 5cbe4c269..f16ca0814 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -290,7 +290,7 @@ namespace libtorrent public: // in debug mode this is set to false by bdecode to indicate that the - // program has not yet queried the type of this entry, and sould not + // program has not yet queried the type of this entry, and should not // assume that it has a certain type. This is asserted in the accessor // functions. This does not apply if exceptions are used. mutable boost::uint8_t m_type_queried:1; diff --git a/include/libtorrent/kademlia/msg.hpp b/include/libtorrent/kademlia/msg.hpp index 607eab4f8..d82b91a47 100644 --- a/include/libtorrent/kademlia/msg.hpp +++ b/include/libtorrent/kademlia/msg.hpp @@ -90,7 +90,7 @@ struct key_desc_t // generate an error response message void TORRENT_EXPORT incoming_error(entry& e, char const* msg, int error_code = 203); -// given a redundent name to avoid clashing with libtorrent::detail +// given a redundant name to avoid clashing with libtorrent::detail namespace dht_detail { bool TORRENT_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[] diff --git a/include/libtorrent/operations.hpp b/include/libtorrent/operations.hpp index 9cb0bad45..524b6648e 100644 --- a/include/libtorrent/operations.hpp +++ b/include/libtorrent/operations.hpp @@ -89,7 +89,7 @@ namespace libtorrent // a call related to bittorrent protocol encryption failed op_encryption, - // an attempt to connect a socket failed + // an attempt to connect a socket failed op_connect, // establishing an SSL connection failed diff --git a/src/kademlia/dht_storage.cpp b/src/kademlia/dht_storage.cpp index ddf8e26fd..57d2fd13c 100644 --- a/src/kademlia/dht_storage.cpp +++ b/src/kademlia/dht_storage.cpp @@ -152,7 +152,7 @@ namespace } } - // return true of the first argument is a better canidate for removal, i.e. + // return true of the first argument is a better candidate for removal, i.e. // less important to keep struct immutable_item_comparator { From b707a4de907e272b42dedb1e1f4f2c72b5bfdb22 Mon Sep 17 00:00:00 2001 From: arvidn Date: Wed, 2 Mar 2016 01:39:46 -0500 Subject: [PATCH 18/29] uphold the invariant that the num_unchoke_slots counter is int max as long as the unchoke slots limit < 0 --- src/choker.cpp | 19 +++++++++++++++---- src/session_impl.cpp | 5 ++--- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/choker.cpp b/src/choker.cpp index d3cf88071..103bd9802 100644 --- a/src/choker.cpp +++ b/src/choker.cpp @@ -133,14 +133,14 @@ namespace libtorrent // when seeding, prefer the peer we're uploading the fastest to c1 = lhs->uploaded_in_last_round(); c2 = rhs->uploaded_in_last_round(); - + // take torrent priority into account c1 *= prio1; c2 *= prio2; if (c1 > c2) return true; if (c2 > c1) return false; - + // prioritize the one that has waited the longest to be unchoked // the round-robin unchoker relies on this logic. Don't change it // without moving this into that unchoker logic @@ -200,7 +200,7 @@ namespace libtorrent ? t2_total - rhs->num_have_pieces() : rhs->num_have_pieces()) * 1000 / t2_total; if (score1 > score2) return true; if (score2 > score1) return false; - + // prioritize the one that has waited the longest to be unchoked // the round-robin unchoker relies on this logic. Don't change it // without moving this into that unchoker logic @@ -215,7 +215,7 @@ namespace libtorrent c1 = lhs->uploaded_in_last_round(); c2 = rhs->uploaded_in_last_round(); - + // take torrent priority into account c1 *= lhs->get_priority(peer_connection::upload_channel); c2 *= rhs->get_priority(peer_connection::upload_channel); @@ -256,7 +256,18 @@ namespace libtorrent , time_duration unchoke_interval , aux::session_settings const& sett) { +#if TORRENT_USE_ASSERTS + for (std::vector::iterator i = peers.begin() + , end(peers.end()); i != end; ++i) + { + TORRENT_ASSERT((*i)->self()); + TORRENT_ASSERT((*i)->associated_torrent().lock()); + } +#endif + int upload_slots = sett.get_int(settings_pack::unchoke_slots_limit); + if (upload_slots < 0) + upload_slots = (std::numeric_limits::max)(); // ==== BitTyrant ==== // diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 07c7270df..82a0477a9 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4195,6 +4195,7 @@ retry: int const allowed_upload_slots = unchoke_sort(peers, max_upload_rate , unchoke_interval, m_settings); + m_stats_counters.set_value(counters::num_unchoke_slots , allowed_upload_slots); @@ -6140,9 +6141,7 @@ retry: void session_impl::update_unchoke_limit() { - int unchoke_limit = m_settings.get_int(settings_pack::unchoke_slots_limit); - - int allowed_upload_slots = unchoke_limit; + int allowed_upload_slots = m_settings.get_int(settings_pack::unchoke_slots_limit); if (allowed_upload_slots < 0) allowed_upload_slots = (std::numeric_limits::max)(); From 2bd6ad9974491de782421809cd455f278d651491 Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 4 Mar 2016 20:20:49 -0500 Subject: [PATCH 19/29] remove invalid assert in the disk thread --- src/block_cache.cpp | 2 +- src/disk_buffer_pool.cpp | 2 +- src/disk_io_thread.cpp | 31 ++++++++----------------------- 3 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/block_cache.cpp b/src/block_cache.cpp index b51f9a923..93a46a957 100644 --- a/src/block_cache.cpp +++ b/src/block_cache.cpp @@ -1083,7 +1083,7 @@ int block_cache::try_evict_blocks(int num, cached_piece_entry* ignore) // the first pass, only evict blocks that have been // hashed if (pass == 0 && pe->hash) - end = pe->hash->offset / block_size(); + end = pe->hash->offset / block_size(); // go through the blocks and evict the ones // that are not dirty and not referenced diff --git a/src/disk_buffer_pool.cpp b/src/disk_buffer_pool.cpp index 769783ebc..4e879dc9f 100644 --- a/src/disk_buffer_pool.cpp +++ b/src/disk_buffer_pool.cpp @@ -473,7 +473,7 @@ namespace libtorrent #endif sett.get_str(settings_pack::mmap_cache).empty()) { - int cache_size = sett.get_int(settings_pack::cache_size); + int const cache_size = sett.get_int(settings_pack::cache_size); if (cache_size < 0) { boost::uint64_t phys_ram = total_physical_ram(); diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index fce117f05..e9db92eaf 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1143,21 +1143,6 @@ namespace libtorrent return; } -#if TORRENT_USE_ASSERTS - // TODO: it should clear the hash state even when there's an error, right? - if (j->action == disk_io_job::hash && !j->error.ec) - { - // a hash job should never return without clearing pe->hash - l.lock(); - cached_piece_entry* pe = m_disk_cache.find_piece(j); - if (pe != NULL) - { - TORRENT_PIECE_ASSERT(pe->hash == NULL, pe); - } - l.unlock(); - } -#endif - if (ret == defer_handler) return; j->ret = ret; @@ -2251,10 +2236,10 @@ namespace libtorrent // just read straight from the file TORRENT_ASSERT(m_magic == 0x1337); - int piece_size = j->storage->files()->piece_size(j->piece); - int block_size = m_disk_cache.block_size(); - int blocks_in_piece = (piece_size + block_size - 1) / block_size; - int file_flags = file_flags_for_job(j); + int const piece_size = j->storage->files()->piece_size(j->piece); + int const block_size = m_disk_cache.block_size(); + int const blocks_in_piece = (piece_size + block_size - 1) / block_size; + int const file_flags = file_flags_for_job(j); file::iovec_t iov; iov.iov_base = m_disk_cache.allocate_buffer("hashing"); @@ -2275,7 +2260,7 @@ namespace libtorrent if (!j->error.ec) { - boost::uint32_t read_time = total_microseconds(clock_type::now() - start_time); + boost::uint32_t const read_time = total_microseconds(clock_type::now() - start_time); m_read_time.add_sample(read_time); m_stats_counters.inc_stats_counter(counters::num_blocks_read); @@ -2302,8 +2287,8 @@ namespace libtorrent if (m_settings.get_int(settings_pack::cache_size) == 0) return do_uncached_hash(j); - int piece_size = j->storage->files()->piece_size(j->piece); - int file_flags = file_flags_for_job(j); + int const piece_size = j->storage->files()->piece_size(j->piece); + int const file_flags = file_flags_for_job(j); mutex::scoped_lock l(m_cache_mutex); @@ -2391,7 +2376,7 @@ namespace libtorrent int block_size = m_disk_cache.block_size(); int blocks_in_piece = (piece_size + block_size - 1) / block_size; - + // keep track of which blocks we have locked by incrementing // their refcounts. This is used to decrement only these blocks // later. From 2efb9d9a6afdf983c7abc51fa738a3c711a239db Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 3 Mar 2016 01:18:49 -0500 Subject: [PATCH 20/29] fix bug in receive_buffer --- src/receive_buffer.cpp | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/receive_buffer.cpp b/src/receive_buffer.cpp index e37aa051c..c9cb16190 100644 --- a/src/receive_buffer.cpp +++ b/src/receive_buffer.cpp @@ -194,29 +194,41 @@ buffer::interval receive_buffer::mutable_buffer() , &m_recv_buffer[0] + m_recv_start + rcv_pos); } -void receive_buffer::mutable_buffers(std::vector& vec, int bytes) +void receive_buffer::mutable_buffers(std::vector& vec, int const bytes) { - using namespace boost; + namespace asio = boost::asio; + + // bytes is the number of bytes we just received, and m_recv_pos has + // already been adjusted for these bytes. The receive pos immediately + // before we received these bytes was (m_recv_pos - bytes) + + int const last_recv_pos = m_recv_pos - bytes; TORRENT_ASSERT(bytes <= m_recv_pos); - int regular_buf_size = regular_buffer_size(); + // the number of bytes in the current packet that are received into + // a regular receive buffer (as opposed to a disk cache buffer) + int const regular_buf_size = regular_buffer_size(); + TORRENT_ASSERT(regular_buf_size >= 0); if (!m_disk_recv_buffer || regular_buf_size >= m_recv_pos) { + // we just received into a regular disk buffer vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start - + m_recv_pos - bytes, bytes)); + + last_recv_pos, bytes)); } - else if (m_recv_pos - bytes >= regular_buf_size) + else if (last_recv_pos >= regular_buf_size) { - vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get() + m_recv_pos - - regular_buf_size - bytes, bytes)); + // we only received into a disk buffer + vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get() + + last_recv_pos - regular_buf_size, bytes)); } else { - TORRENT_ASSERT(m_recv_pos - bytes < regular_buf_size); + // we received into a regular and a disk buffer + TORRENT_ASSERT(last_recv_pos < regular_buf_size); TORRENT_ASSERT(m_recv_pos > regular_buf_size); - vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start + m_recv_pos - bytes - , regular_buf_size - (m_recv_start + m_recv_pos - bytes))); + vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start + last_recv_pos + , regular_buf_size - last_recv_pos)); vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get() , m_recv_pos - regular_buf_size)); } From 26f88bb12d1fd361c1c4746e37eab8396272d98a Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 3 Mar 2016 23:53:24 -0500 Subject: [PATCH 21/29] add receive_buffer unit test and some more cleanup and asserts --- include/libtorrent/receive_buffer.hpp | 18 +- src/bt_peer_connection.cpp | 1 - src/receive_buffer.cpp | 60 +++--- test/Jamfile | 1 + test/Makefile.am | 1 + test/test_receive_buffer.cpp | 255 ++++++++++++++++++++++++++ 6 files changed, 310 insertions(+), 26 deletions(-) create mode 100644 test/test_receive_buffer.cpp diff --git a/include/libtorrent/receive_buffer.hpp b/include/libtorrent/receive_buffer.hpp index b35a6cdd0..db377ae9d 100644 --- a/include/libtorrent/receive_buffer.hpp +++ b/include/libtorrent/receive_buffer.hpp @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { -struct receive_buffer +struct TORRENT_EXTRA_EXPORT receive_buffer { friend struct crypto_receive_buffer; @@ -58,6 +58,7 @@ struct receive_buffer int packet_bytes_remaining() const { TORRENT_ASSERT(m_recv_start == 0); + TORRENT_ASSERT(m_packet_size > 0); return m_packet_size - m_recv_pos; } @@ -67,13 +68,19 @@ struct receive_buffer int pos() const { return m_recv_pos; } int capacity() const { return m_recv_buffer.capacity() + m_disk_recv_buffer_size; } - int regular_buffer_size() const { return m_packet_size - m_disk_recv_buffer_size; } + int regular_buffer_size() const + { + TORRENT_ASSERT(m_packet_size > 0); + return m_packet_size - m_disk_recv_buffer_size; + } // regular buffer only boost::asio::mutable_buffer reserve(int size); // with possible disk buffer usage int reserve(boost::array& vec, int size); + // tell the buffer we just receved more bytes at the end of it. This will + // advance the end cursor void received(int bytes_transferred) { TORRENT_ASSERT(m_packet_size > 0); @@ -82,9 +89,14 @@ struct receive_buffer + m_disk_recv_buffer_size)); } + // tell the buffer we consumed some bytes of it. This will advance the read + // cursor int advance_pos(int bytes); + + // has the read cursor reached the end cursor? bool pos_at_end() { return m_recv_pos == m_recv_end; } + // make the buffer size dividible by 8 bytes (RC4 block size) void clamp_size(); void set_soft_packet_size(int size) { m_soft_packet_size = size; } @@ -94,6 +106,8 @@ struct receive_buffer // offset = the offset into the receive buffer where to remove `size` bytes void cut(int size, int packet_size, int offset = 0); + // return the interval between the start of the buffer to the read cursor. + // This is the "current" packet. buffer::const_interval get() const; #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 729a37041..113a85d6b 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -3284,7 +3284,6 @@ namespace libtorrent if (!m_recv_buffer.packet_finished()) return; recv_buffer = m_recv_buffer.get(); - #ifndef TORRENT_DISABLE_LOGGING std::string extensions; extensions.resize(8 * 8); diff --git a/src/receive_buffer.cpp b/src/receive_buffer.cpp index c9cb16190..d5e86a67d 100644 --- a/src/receive_buffer.cpp +++ b/src/receive_buffer.cpp @@ -54,8 +54,12 @@ boost::asio::mutable_buffer receive_buffer::reserve(int size) { TORRENT_ASSERT(size > 0); TORRENT_ASSERT(!m_disk_recv_buffer); - m_recv_buffer.resize(m_recv_pos + size); - return boost::asio::buffer(&m_recv_buffer[m_recv_pos], size); + // this is unintuitive, but we used to use m_recv_pos in this function when + // we should have used m_recv_end. perhaps they always happen to be equal + TORRENT_ASSERT(m_recv_pos == m_recv_end); + + m_recv_buffer.resize(m_recv_end + size); + return boost::asio::buffer(&m_recv_buffer[0] + m_recv_end, size); } int receive_buffer::reserve(boost::array& vec, int size) @@ -64,41 +68,48 @@ int receive_buffer::reserve(boost::array& vec, i TORRENT_ASSERT(m_recv_pos >= 0); TORRENT_ASSERT(m_packet_size > 0); + // normalize() must be called before receiving more data + TORRENT_ASSERT(m_recv_start == 0); + + // this is unintuitive, but we used to use m_recv_pos in this function when + // we should have used m_recv_end. perhaps they always happen to be equal + TORRENT_ASSERT(m_recv_pos == m_recv_end); + int num_bufs; - int regular_buf_size = regular_buffer_size(); + int const regular_buf_size = regular_buffer_size(); if (int(m_recv_buffer.size()) < regular_buf_size) m_recv_buffer.resize(round_up8(regular_buf_size)); - if (!m_disk_recv_buffer || regular_buf_size >= m_recv_pos + size) + if (!m_disk_recv_buffer || regular_buf_size >= m_recv_end + size) { // only receive into regular buffer - TORRENT_ASSERT(m_recv_pos + size <= int(m_recv_buffer.size())); - vec[0] = boost::asio::buffer(&m_recv_buffer[m_recv_pos], size); + TORRENT_ASSERT(m_recv_end + size <= int(m_recv_buffer.size())); + vec[0] = boost::asio::buffer(&m_recv_buffer[0] + m_recv_end, size); TORRENT_ASSERT(boost::asio::buffer_size(vec[0]) > 0); num_bufs = 1; } - else if (m_recv_pos >= regular_buf_size) + else if (m_recv_end >= regular_buf_size) { // only receive into disk buffer - TORRENT_ASSERT(m_recv_pos - regular_buf_size >= 0); - TORRENT_ASSERT(m_recv_pos - regular_buf_size + size <= m_disk_recv_buffer_size); - vec[0] = boost::asio::buffer(m_disk_recv_buffer.get() + m_recv_pos - regular_buf_size, size); + TORRENT_ASSERT(m_recv_end - regular_buf_size >= 0); + TORRENT_ASSERT(m_recv_end - regular_buf_size + size <= m_disk_recv_buffer_size); + vec[0] = boost::asio::buffer(m_disk_recv_buffer.get() + m_recv_end - regular_buf_size, size); TORRENT_ASSERT(boost::asio::buffer_size(vec[0]) > 0); num_bufs = 1; } else { // receive into both regular and disk buffer - TORRENT_ASSERT(size + m_recv_pos > regular_buf_size); - TORRENT_ASSERT(m_recv_pos < regular_buf_size); + TORRENT_ASSERT(size + m_recv_end > regular_buf_size); + TORRENT_ASSERT(m_recv_end < regular_buf_size); TORRENT_ASSERT(size - regular_buf_size - + m_recv_pos <= m_disk_recv_buffer_size); + + m_recv_end <= m_disk_recv_buffer_size); - vec[0] = boost::asio::buffer(&m_recv_buffer[m_recv_pos] - , regular_buf_size - m_recv_pos); + vec[0] = boost::asio::buffer(&m_recv_buffer[0] + m_recv_end + , regular_buf_size - m_recv_end); vec[1] = boost::asio::buffer(m_disk_recv_buffer.get() - , size - regular_buf_size + m_recv_pos); + , size - regular_buf_size + m_recv_end); TORRENT_ASSERT(boost::asio::buffer_size(vec[0]) + boost::asio::buffer_size(vec[1])> 0); num_bufs = 2; @@ -109,9 +120,9 @@ int receive_buffer::reserve(boost::array& vec, i int receive_buffer::advance_pos(int bytes) { - int packet_size = m_soft_packet_size ? m_soft_packet_size : m_packet_size; - int limit = packet_size > m_recv_pos ? packet_size - m_recv_pos : packet_size; - int sub_transferred = (std::min)(bytes, limit); + int const packet_size = m_soft_packet_size ? m_soft_packet_size : m_packet_size; + int const limit = packet_size > m_recv_pos ? packet_size - m_recv_pos : packet_size; + int const sub_transferred = (std::min)(bytes, limit); m_recv_pos += sub_transferred; if (m_recv_pos >= m_soft_packet_size) m_soft_packet_size = 0; return sub_transferred; @@ -174,7 +185,8 @@ buffer::const_interval receive_buffer::get() const TORRENT_ASSERT(m_recv_pos == 0); return buffer::interval(0,0); } - int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size())); + + int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()) - m_recv_start); return buffer::const_interval(&m_recv_buffer[0] + m_recv_start , &m_recv_buffer[0] + m_recv_start + rcv_pos); } @@ -194,6 +206,8 @@ buffer::interval receive_buffer::mutable_buffer() , &m_recv_buffer[0] + m_recv_start + rcv_pos); } +// TODO: 2 should this take a boost::array<..., 2> instead? it could return the +// number of buffers added, just like reserve. void receive_buffer::mutable_buffers(std::vector& vec, int const bytes) { namespace asio = boost::asio; @@ -205,8 +219,8 @@ void receive_buffer::mutable_buffers(std::vector& v int const last_recv_pos = m_recv_pos - bytes; TORRENT_ASSERT(bytes <= m_recv_pos); - // the number of bytes in the current packet that are received into - // a regular receive buffer (as opposed to a disk cache buffer) + // the number of bytes in the current packet that are being received into a + // regular receive buffer (as opposed to a disk cache buffer) int const regular_buf_size = regular_buffer_size(); TORRENT_ASSERT(regular_buf_size >= 0); @@ -233,7 +247,7 @@ void receive_buffer::mutable_buffers(std::vector& v , m_recv_pos - regular_buf_size)); } -#if defined TORRENT_DEBUG || defined TORRENT_RELEASE_ASSERTS +#if TORRENT_USE_ASSERTS int vec_bytes = 0; for (std::vector::iterator i = vec.begin(); i != vec.end(); ++i) diff --git a/test/Jamfile b/test/Jamfile index 1281f4735..4d89d2e09 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -154,6 +154,7 @@ test-suite libtorrent : test_linked_list.cpp test_file_progress.cpp ] + [ run test_receive_buffer.cpp ] [ run test_alert_manager.cpp ] [ run test_direct_dht.cpp ] [ run test_magnet.cpp ] diff --git a/test/Makefile.am b/test/Makefile.am index 4e6ae74b2..35b3a3258 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -18,6 +18,7 @@ test_programs = \ test_pe_crypto \ test_pex \ test_read_piece \ + test_receive_buffer \ test_resume \ test_ssl \ test_storage \ diff --git a/test/test_receive_buffer.cpp b/test/test_receive_buffer.cpp new file mode 100644 index 000000000..7059864a0 --- /dev/null +++ b/test/test_receive_buffer.cpp @@ -0,0 +1,255 @@ +/* + +Copyright (c) 2016, 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/config.hpp" +#include "test.hpp" +#include "libtorrent/receive_buffer.hpp" + +using namespace libtorrent; + +struct allocator : buffer_allocator_interface +{ + void free_disk_buffer(char*) {} + char* allocate_disk_buffer(char const*) { TORRENT_ASSERT(false); return NULL; } + char* allocate_disk_buffer(bool& + , boost::shared_ptr + , char const*) { TORRENT_ASSERT(false); return NULL; } + char* async_allocate_disk_buffer(char const* + , boost::function const&) { TORRENT_ASSERT(false); return NULL; } + void reclaim_block(block_cache_reference ref) {} +}; + +TORRENT_TEST(recv_buffer_init) +{ + allocator a; + receive_buffer b(a); + + b.cut(0, 10); + + TEST_EQUAL(b.packet_size(), 10); + TEST_EQUAL(b.packet_bytes_remaining(), 10); + TEST_EQUAL(b.packet_finished(), false); + TEST_EQUAL(b.pos(), 0); + TEST_EQUAL(b.capacity(), 0); +} + +TORRENT_TEST(recv_buffer_pos_at_end_false) +{ + allocator a; + receive_buffer b(a); + + b.cut(0, 1000); + // allocate some space to receive into + boost::array vec; + int num_bufs = b.reserve(vec, 1000); + + // since we don't have a disk buffer, there should only be a single + // range/buffer + TEST_EQUAL(num_bufs, 1); + + b.received(1000); + b.advance_pos(999); + + TEST_EQUAL(b.pos_at_end(), false); +} + +TORRENT_TEST(recv_buffer_pos_at_end_true) +{ + allocator a; + receive_buffer b(a); + b.cut(0, 1000); + b.reserve(1000); + boost::array vec; + int num_bufs = b.reserve(vec, 1000); + TEST_EQUAL(num_bufs, 1); + b.received(1000); + b.advance_pos(1000); + TEST_EQUAL(b.pos_at_end(), true); +} + +TORRENT_TEST(recv_buffer_packet_finished) +{ + allocator a; + receive_buffer b(a); + // packet_size = 10 + b.cut(0, 10); + b.reserve(1000); + boost::array vec; + int num_bufs = b.reserve(vec, 1000); + TEST_EQUAL(num_bufs, 1); + b.received(1000); + + for (int i = 0; i < 10; ++i) + { + TEST_EQUAL(b.packet_finished(), false); + b.advance_pos(1); + } + TEST_EQUAL(b.packet_finished(), true); +} + +TORRENT_TEST(recv_buffer_disk_buffer) +{ + char disk_buffer; // fake disk buffer pointer + + allocator a; + receive_buffer b(a); + b.reserve(1000); + b.cut(0, 1000); // packet size = 1000 + boost::array vec; + b.assign_disk_buffer(&disk_buffer, 137); + int num_bufs = b.reserve(vec, 1000); + TEST_EQUAL(num_bufs, 2); + + // regular buffer disk buffer + // -----------------====== + // + // |----------------------| 1000 + // |-----| 137 + // |----------------| 863 + + TEST_EQUAL(boost::asio::buffer_size(vec[0]), 863); + TEST_EQUAL(boost::asio::buffer_size(vec[1]), 137); +} + +#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) + +TORRENT_TEST(recv_buffer_mutable_buffers_regular_and_disk) +{ + char disk_buffer; // fake disk buffer pointer + + allocator a; + receive_buffer b(a); + b.reserve(1100); + b.cut(0, 100); // packet size = 100 + b.received(1100); + int packet_transferred = b.advance_pos(1100); + // this is just the first packet + TEST_EQUAL(packet_transferred, 100); + // the next packet is 1000, and we're done with the first 100 bytes now + b.cut(100, 1000); // packet size = 1000 + // and it has a disk buffer + b.assign_disk_buffer(&disk_buffer, 137); + std::vector vec; + packet_transferred = b.advance_pos(999); + TEST_EQUAL(packet_transferred, 999); + b.mutable_buffers(vec, 999); + TEST_EQUAL(vec.size(), 2); + + // previous packet + // | + // v regular buffer disk buffer + // - - - -----------------====== + // ^ + // | + // m_recv_start + + // |----------------------| 1000 packet size + // |-----| 137 disk buffer + // |----------------| 863 regular buffer + + TEST_EQUAL(boost::asio::buffer_size(vec[0]), 863); + TEST_EQUAL(boost::asio::buffer_size(vec[1]), 137 - 1); + TEST_EQUAL(boost::asio::buffer_size(vec[0]) + + boost::asio::buffer_size(vec[1]), 999); +} + +TORRENT_TEST(recv_buffer_mutable_buffers_regular_only) +{ + allocator a; + receive_buffer b(a); + b.reserve(1100); + b.cut(0, 100); // packet size = 100 + b.received(1100); + int packet_transferred = b.advance_pos(1100); + // this is just the first packet + TEST_EQUAL(packet_transferred, 100); + // the next packet is 1000, and we're done with the first 100 bytes now + b.cut(100, 1000); // packet size = 1000 + std::vector vec; + packet_transferred = b.advance_pos(999); + TEST_EQUAL(packet_transferred, 999); + b.mutable_buffers(vec, 999); + TEST_EQUAL(vec.size(), 1); + + // previous packet + // | + // v regular buffer + // - - - ----------------------- + // ^ + // | + // m_recv_start + + // |----------------------| 1000 packet size + // |---------------------| 999 regular buffer + + TEST_EQUAL(boost::asio::buffer_size(vec[0]), 999); +} + +TORRENT_TEST(recv_buffer_mutable_buffers_disk) +{ + char disk_buffer; // fake disk buffer pointer + + allocator a; + receive_buffer b(a); + b.reserve(1100); + b.cut(0, 100); // packet size = 100 + b.received(1100); + int packet_transferred = b.advance_pos(1100); + // this is just the first packet + TEST_EQUAL(packet_transferred, 100); + // the next packet is 1000, and we're done with the first 100 bytes now + b.cut(100, 1000); // packet size = 1000 + // and it has a disk buffer + b.assign_disk_buffer(&disk_buffer, 1000); + std::vector vec; + packet_transferred = b.advance_pos(999); + TEST_EQUAL(packet_transferred, 999); + b.mutable_buffers(vec, 999); + TEST_EQUAL(vec.size(), 1); + + // previous packet + // | + // v disk buffer + // - - - ======================= + // ^ + // | + // m_recv_start + + // |----------------------| 1000 packet size + // |----------------------| 999 disk buffer + + TEST_EQUAL(boost::asio::buffer_size(vec[0]), 999); + TEST_EQUAL(boost::asio::buffer_cast(vec[0]), &disk_buffer); +} + +#endif + From 8ca76f9d595ee507a123c6d3536a682b0560685f Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 5 Mar 2016 11:02:41 -0500 Subject: [PATCH 22/29] fix support for auto disk cache size and disk buffer pool allocator behavior --- examples/client_test.cpp | 4 +-- simulation/test_swarm.cpp | 2 +- simulation/test_transfer.cpp | 50 ++++++++++++++++++++++++++++++++++++ src/disk_buffer_pool.cpp | 15 ++++++++--- src/disk_io_thread.cpp | 14 +++++----- src/session_stats.cpp | 4 +-- 6 files changed, 73 insertions(+), 16 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index e9e719023..403f473ba 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1451,8 +1451,8 @@ int main(int argc, char* argv[]) #endif // TORRENT_USE_I2P case 'C': settings.set_int(settings_pack::cache_size, atoi(arg)); - settings.set_bool(settings_pack::use_read_cache, atoi(arg) > 0); - settings.set_int(settings_pack::cache_buffer_chunk_size, atoi(arg) / 100); + settings.set_bool(settings_pack::use_read_cache, atoi(arg) != 0); + settings.set_int(settings_pack::cache_buffer_chunk_size, 0); break; case 'A': settings.set_int(settings_pack::allowed_fast_set_size, atoi(arg)); break; case 'R': settings.set_int(settings_pack::read_cache_line_size, atoi(arg)); break; diff --git a/simulation/test_swarm.cpp b/simulation/test_swarm.cpp index d8ca4fb1e..e8d2d9bab 100644 --- a/simulation/test_swarm.cpp +++ b/simulation/test_swarm.cpp @@ -97,7 +97,7 @@ TORRENT_TEST(session_stats) // on alert , [=](lt::alert const* a, lt::session& ses) { - lt::session_stats_alert const* ss = lt::alert_cast(a); + auto const* ss = lt::alert_cast(a); if (!ss) return; // there's one downloading torrent diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index e3d519aee..a783e4b8a 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "create_torrent.hpp" #include "settings.hpp" #include "libtorrent/session.hpp" +#include "libtorrent/session_stats.hpp" #include "libtorrent/deadline_timer.hpp" #include "libtorrent/settings_pack.hpp" #include "libtorrent/ip_filter.hpp" @@ -194,6 +195,39 @@ void filter_ips(lt::session& ses) ses.set_ip_filter(filter); } +void set_cache_size(lt::session& ses, int val) +{ + using namespace libtorrent; + settings_pack pack; + pack.set_int(settings_pack::cache_size, val); + ses.apply_settings(pack); +} + +int get_cache_size(lt::session& ses) +{ + using namespace libtorrent; + std::vector stats = session_stats_metrics(); + int const read_cache_idx = find_metric_idx("disk.read_cache_blocks"); + int const write_cache_idx = find_metric_idx("disk.write_cache_blocks"); + TEST_CHECK(read_cache_idx >= 0); + TEST_CHECK(write_cache_idx >= 0); + ses.set_alert_notify([](){}); + ses.post_session_stats(); + std::vector alerts; + ses.pop_alerts(&alerts); + int cache_size = -1; + for (auto const a : alerts) + { + if (auto const* st = alert_cast(a)) + { + cache_size = st->values[read_cache_idx]; + cache_size += st->values[write_cache_idx]; + break; + } + } + return cache_size; +} + void set_proxy(lt::session& ses, int proxy_type, int flags = 0, bool proxy_peer_connections = true) { // apply the proxy settings to session 0 @@ -391,3 +425,19 @@ TORRENT_TEST(no_proxy_utp_banned) ); } +TORRENT_TEST(auto_disk_cache_size) +{ + using namespace libtorrent; + run_test( + [](lt::session& ses0, lt::session& ses1) { set_cache_size(ses0, -1); }, + [](lt::session& ses, lt::alert const* alert) {}, + [](std::shared_ptr ses[2]) { + TEST_EQUAL(is_seed(*ses[0]), true); + + int const cache_size = get_cache_size(*ses[0]); + printf("cache size: %d\n", cache_size); + // this assumes the test torrent is at least 4 blocks + TEST_CHECK(cache_size > 4); + } + ); +} diff --git a/src/disk_buffer_pool.cpp b/src/disk_buffer_pool.cpp index 4e879dc9f..642c55477 100644 --- a/src/disk_buffer_pool.cpp +++ b/src/disk_buffer_pool.cpp @@ -371,11 +371,14 @@ namespace libtorrent #else if (m_using_pool_allocator) { - ret = static_cast(m_pool.malloc()); - int effective_block_size = m_cache_buffer_chunk_size + int const effective_block_size + = m_in_use >= m_max_use + ? 20 // use small increments once we've exceeded the cache size + : m_cache_buffer_chunk_size ? m_cache_buffer_chunk_size : (std::max)(m_max_use / 10, 1); m_pool.set_next_size(effective_block_size); + ret = static_cast(m_pool.malloc()); } else { @@ -453,7 +456,9 @@ namespace libtorrent m_cache_buffer_chunk_size = sett.get_int(settings_pack::cache_buffer_chunk_size); m_lock_disk_cache = sett.get_bool(settings_pack::lock_disk_cache); #ifndef TORRENT_DISABLE_POOL_ALLOCATOR - m_want_pool_allocator = sett.get_bool(settings_pack::use_disk_cache_pool); + // if the chunk size is set to 1, there's no point in creating a pool + m_want_pool_allocator = sett.get_bool(settings_pack::use_disk_cache_pool) + && (m_cache_buffer_chunk_size != 1); // if there are no allocated blocks, it's OK to switch allocator if (m_in_use == 0) m_using_pool_allocator = m_want_pool_allocator; @@ -476,7 +481,7 @@ namespace libtorrent int const cache_size = sett.get_int(settings_pack::cache_size); if (cache_size < 0) { - boost::uint64_t phys_ram = total_physical_ram(); + boost::uint64_t const phys_ram = total_physical_ram(); if (phys_ram == 0) m_max_use = 1024; else m_max_use = phys_ram / 8 / m_block_size; @@ -500,6 +505,8 @@ namespace libtorrent m_exceeded_max_size = true; m_trigger_cache_trim(); } + if (m_cache_buffer_chunk_size > m_max_use) + m_cache_buffer_chunk_size = m_max_use; } #if TORRENT_USE_ASSERTS diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index e9db92eaf..f45d83d48 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1188,7 +1188,7 @@ namespace libtorrent int disk_io_thread::do_read(disk_io_job* j, jobqueue_t& completed_jobs) { - if (!m_settings.get_bool(settings_pack::use_read_cache) + if (m_settings.get_bool(settings_pack::use_read_cache) == false || m_settings.get_int(settings_pack::cache_size) == 0) { // we're not using a cache. This is the simple path @@ -1462,7 +1462,7 @@ namespace libtorrent // should we put this write job in the cache? // if we don't use the cache we shouldn't. if (m_settings.get_bool(settings_pack::use_write_cache) - && m_settings.get_int(settings_pack::cache_size) > 0) + && m_settings.get_int(settings_pack::cache_size) != 0) { mutex::scoped_lock l(m_cache_mutex); @@ -1578,7 +1578,7 @@ namespace libtorrent TORRENT_ASSERT(j->action == disk_io_job::read); if (m_settings.get_bool(settings_pack::use_read_cache) - && m_settings.get_int(settings_pack::cache_size) > 0) + && m_settings.get_int(settings_pack::cache_size) != 0) { int ret = m_disk_cache.try_read(j); if (ret >= 0) @@ -1691,7 +1691,7 @@ namespace libtorrent TORRENT_ASSERT(m_disk_cache.is_disk_buffer(j->buffer.disk_block)); l_.unlock(); #endif - if (m_settings.get_int(settings_pack::cache_size) > 0 + if (m_settings.get_int(settings_pack::cache_size) != 0 && m_settings.get_bool(settings_pack::use_write_cache)) { TORRENT_ASSERT((r.start % m_disk_cache.block_size()) == 0); @@ -2327,7 +2327,7 @@ namespace libtorrent } } - if (pe == NULL && !m_settings.get_bool(settings_pack::use_read_cache)) + if (pe == NULL && m_settings.get_bool(settings_pack::use_read_cache) == false) { l.unlock(); // if there's no piece in the cache, and the read cache is disabled @@ -2635,7 +2635,7 @@ namespace libtorrent { INVARIANT_CHECK; TORRENT_ASSERT(j->buffer.disk_block == 0); - + if (m_settings.get_int(settings_pack::cache_size) == 0 || m_settings.get_bool(settings_pack::use_read_cache) == false) return 0; @@ -3463,7 +3463,7 @@ namespace libtorrent if (j->action == disk_io_job::read && m_settings.get_bool(settings_pack::use_read_cache) - && m_settings.get_int(settings_pack::cache_size) > 0) + && m_settings.get_int(settings_pack::cache_size) != 0) { int state = prep_read_job_impl(j, false); switch (state) diff --git a/src/session_stats.cpp b/src/session_stats.cpp index 8bcf801a2..9d7e31643 100644 --- a/src/session_stats.cpp +++ b/src/session_stats.cpp @@ -355,10 +355,10 @@ namespace libtorrent // the total number of blocks run through SHA-1 hashing METRIC(disk, num_blocks_hashed) - + // the number of blocks read from the disk cache METRIC(disk, num_blocks_cache_hits) - + // the number of disk I/O operation for reads and writes. One disk // operation may transfer more then one block. METRIC(disk, num_write_ops) From a02c1d2164a6a1d1c57750a190d3ab556bad2ee4 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 5 Mar 2016 17:16:46 -0500 Subject: [PATCH 23/29] record cache settings in the job instead of checking it twice for more robust behavior --- include/libtorrent/disk_io_job.hpp | 6 +++++- simulation/test_transfer.cpp | 17 +++++++++++++++++ src/disk_io_thread.cpp | 21 +++++++++++---------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/include/libtorrent/disk_io_job.hpp b/include/libtorrent/disk_io_job.hpp index fdb693f2c..ded630b6f 100644 --- a/include/libtorrent/disk_io_job.hpp +++ b/include/libtorrent/disk_io_job.hpp @@ -136,7 +136,11 @@ namespace libtorrent in_progress = 0x20, // turns into file::coalesce_buffers in the file operation - coalesce_buffers = 0x40 + coalesce_buffers = 0x40, + + // the disk cache was enabled when this job was issued, it should use + // the disk cache once it's handled by a disk thread + use_disk_cache = 0x80 }; // for write jobs, returns true if its block diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index a783e4b8a..ddae108ba 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -441,3 +441,20 @@ TORRENT_TEST(auto_disk_cache_size) } ); } + +TORRENT_TEST(disable_disk_cache) +{ + using namespace libtorrent; + run_test( + [](lt::session& ses0, lt::session& ses1) { set_cache_size(ses0, 0); }, + [](lt::session& ses, lt::alert const* alert) {}, + [](std::shared_ptr ses[2]) { + TEST_EQUAL(is_seed(*ses[0]), true); + + int const cache_size = get_cache_size(*ses[0]); + printf("cache size: %d\n", cache_size); + TEST_EQUAL(cache_size, 0); + } + ); +} + diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index f45d83d48..57ac499c0 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -1188,16 +1188,11 @@ namespace libtorrent int disk_io_thread::do_read(disk_io_job* j, jobqueue_t& completed_jobs) { - if (m_settings.get_bool(settings_pack::use_read_cache) == false - || m_settings.get_int(settings_pack::cache_size) == 0) + if ((j->flags & disk_io_job::use_disk_cache) == 0) { // we're not using a cache. This is the simple path // just read straight from the file int ret = do_uncached_read(j); - - mutex::scoped_lock l(m_cache_mutex); - cached_piece_entry* pe = m_disk_cache.find_piece(j); - if (pe) maybe_issue_queued_read_jobs(pe, completed_jobs); return ret; } @@ -1461,8 +1456,7 @@ namespace libtorrent // should we put this write job in the cache? // if we don't use the cache we shouldn't. - if (m_settings.get_bool(settings_pack::use_write_cache) - && m_settings.get_int(settings_pack::cache_size) != 0) + if (j->flags & disk_io_job::use_disk_cache) { mutex::scoped_lock l(m_cache_mutex); @@ -1615,7 +1609,7 @@ namespace libtorrent j->error.operation = storage_error::read; return 0; } - + j->flags |= disk_io_job::use_disk_cache; if (pe->outstanding_read) { TORRENT_PIECE_ASSERT(j->piece == pe->piece, pe); @@ -1695,6 +1689,7 @@ namespace libtorrent && m_settings.get_bool(settings_pack::use_write_cache)) { TORRENT_ASSERT((r.start % m_disk_cache.block_size()) == 0); + j->flags |= disk_io_job::use_disk_cache; if (storage->is_blocked(j)) { @@ -1784,6 +1779,12 @@ namespace libtorrent } l.unlock(); + if (m_settings.get_bool(settings_pack::use_read_cache) + && m_settings.get_int(settings_pack::cache_size) != 0) + { + j->flags |= disk_io_job::use_disk_cache; + } + add_job(j); } @@ -2284,7 +2285,7 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_settings.get_int(settings_pack::cache_size) == 0) + if ((j->flags & disk_io_job::use_disk_cache) == 0) return do_uncached_hash(j); int const piece_size = j->storage->files()->piece_size(j->piece); From adf56344e65479ba386f8be9afb30bfc9cf44b0e Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 5 Mar 2016 23:16:33 -0500 Subject: [PATCH 24/29] add interactive option to toggle use of disk cache to client_test --- examples/client_test.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 403f473ba..cfff11bb1 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -606,6 +606,7 @@ std::string bind_to_interface = ""; int poll_interval = 5; int max_connections_per_torrent = 50; bool seed_mode = false; +int cache_size = 1024; bool share_mode = false; bool disable_storage = false; @@ -1296,6 +1297,7 @@ int main(int argc, char* argv[]) namespace lt = libtorrent; settings_pack settings; + settings.set_int(settings_pack::cache_size, cache_size); settings.set_int(settings_pack::active_loaded_limit, 20); settings.set_int(settings_pack::choking_algorithm, settings_pack::rate_based_choker); @@ -1450,8 +1452,8 @@ int main(int argc, char* argv[]) } #endif // TORRENT_USE_I2P case 'C': - settings.set_int(settings_pack::cache_size, atoi(arg)); - settings.set_bool(settings_pack::use_read_cache, atoi(arg) != 0); + cache_size = atoi(arg); + settings.set_int(settings_pack::cache_size, cache_size); settings.set_int(settings_pack::cache_buffer_chunk_size, 0); break; case 'A': settings.set_int(settings_pack::allowed_fast_set_size, atoi(arg)); break; @@ -1923,6 +1925,13 @@ int main(int argc, char* argv[]) if (c == '5') print_peer_rate = !print_peer_rate; if (c == '6') print_fails = !print_fails; if (c == '7') print_send_bufs = !print_send_bufs; + if (c == 'C') + { + cache_size = (cache_size == 0) ? -1 : 0; + settings_pack p; + p.set_int(settings_pack::cache_size, cache_size); + ses.apply_settings(p); + } if (c == 'h') { clear_screen(); @@ -1933,7 +1942,7 @@ int main(int argc, char* argv[]) "[q] quit client [m] add magnet link\n" "\n" "TORRENT ACTIONS\n" - "[p] pause/unpause selected torrent\n" + "[p] pause/unpause selected torrent [C] toggle disk cache\n" "[s] toggle sequential download [j] force recheck\n" "[space] toggle session pause [c] clear error\n" "[v] scrape [D] delete torrent and data\n" From b40430f17583c8a835afcd202092cd6120979acc Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 6 Mar 2016 01:42:46 -0500 Subject: [PATCH 25/29] change the cache size calculation for auto cache size (-1) to be smaller, especially for machines with large amounts of RAM --- src/disk_buffer_pool.cpp | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/disk_buffer_pool.cpp b/src/disk_buffer_pool.cpp index 642c55477..79486d75e 100644 --- a/src/disk_buffer_pool.cpp +++ b/src/disk_buffer_pool.cpp @@ -481,9 +481,35 @@ namespace libtorrent int const cache_size = sett.get_int(settings_pack::cache_size); if (cache_size < 0) { - boost::uint64_t const phys_ram = total_physical_ram(); + boost::uint64_t phys_ram = total_physical_ram(); if (phys_ram == 0) m_max_use = 1024; - else m_max_use = phys_ram / 8 / m_block_size; + else + { + // this is the logic to calculate the automatic disk cache size + // based on the amount of physical RAM. + // The more physical RAM, the smaller portion of it is allocated + // for the cache. + + // we take a 30th of everything exceeding 4 GiB + // a 20th of everything exceeding 1 GiB + // and a 10th of everything below a GiB + + boost::int64_t const gb = 1024 * 1024 * 1024; + + boost::int64_t result = 0; + if (phys_ram > 4 * gb) + { + result += (phys_ram - 4 * gb) / 30; + phys_ram = 4 * gb; + } + if (phys_ram > 1 * gb) + { + result += (phys_ram - 1 * gb) / 20; + phys_ram = 1 * gb; + } + result += phys_ram / 10; + m_max_use = result / m_block_size; + } if (sizeof(void*) == 4) { From 67774d660d09748d8b2deb9d82bc7769216535b2 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 6 Mar 2016 16:31:18 -0500 Subject: [PATCH 26/29] always keep at least 2 async hash jobs outstanding when rechecking torrents (to keep the bandwidth delay product full) --- src/disk_io_thread.cpp | 12 ++++++------ src/torrent.cpp | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/disk_io_thread.cpp b/src/disk_io_thread.cpp index 57ac499c0..9845a67e0 100644 --- a/src/disk_io_thread.cpp +++ b/src/disk_io_thread.cpp @@ -573,7 +573,7 @@ namespace libtorrent int piece_size = pe->storage->files()->piece_size(pe->piece); TORRENT_PIECE_ASSERT(piece_size > 0, pe); - + int iov_len = 0; // the blocks we're flushing int num_flushing = 0; @@ -2839,17 +2839,17 @@ namespace libtorrent if (no_pieces == false) { int block_size = m_disk_cache.block_size(); - + if (storage) { ret->pieces.reserve(storage->num_pieces()); - + for (boost::unordered_set::iterator i = storage->cached_pieces().begin(), end(storage->cached_pieces().end()); i != end; ++i) { TORRENT_ASSERT((*i)->storage.get() == storage); - + if ((*i)->cache_state == cached_piece_entry::read_lru2_ghost || (*i)->cache_state == cached_piece_entry::read_lru1_ghost) continue; @@ -2860,10 +2860,10 @@ namespace libtorrent else { ret->pieces.reserve(m_disk_cache.num_pieces()); - + std::pair range = m_disk_cache.all_pieces(); - + for (block_cache::iterator i = range.first; i != range.second; ++i) { if (i->cache_state == cached_piece_entry::read_lru2_ghost diff --git a/src/torrent.cpp b/src/torrent.cpp index e51edbc66..b9c99794c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2682,7 +2682,10 @@ namespace libtorrent int num_outstanding = settings().get_int(settings_pack::checking_mem_usage) * block_size() / m_torrent_file->piece_length(); - if (num_outstanding <= 0) num_outstanding = 1; + // if we only keep a single read operation in-flight at a time, we suffer + // significant performance degradation. Always keep at least two jobs + // outstanding + if (num_outstanding < 2) num_outstanding = 2; // we might already have some outstanding jobs, if we were paused and // resumed quickly, before the outstanding jobs completed From 442979c3186ea02ceceb738cf673aa55d828fb87 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 5 Mar 2016 15:15:22 -0500 Subject: [PATCH 27/29] support filtering which parts of session state are loaded by load_state() --- ChangeLog | 1 + bindings/python/src/session.cpp | 26 +-- examples/client_test.cpp | 16 +- include/libtorrent/aux_/session_impl.hpp | 2 +- include/libtorrent/entry.hpp | 2 +- include/libtorrent/session_handle.hpp | 20 +-- src/session_handle.cpp | 15 +- src/session_impl.cpp | 194 +++++++++++++---------- test/test_session.cpp | 105 ++++++++++++ 9 files changed, 259 insertions(+), 122 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1dca747ea..e5db9c4ba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 1.1.0 release + * support filtering which parts of session state are loaded by load_state() * deprecate support for adding torrents by HTTP URL * allow specifying which tracker to scrape in scrape_tracker * tracker response alerts from user initiated announces/scrapes are now diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 1ee47db8f..57ff83a1a 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -529,18 +529,18 @@ namespace } #endif - void load_state(lt::session& ses, entry const& st) - { - allow_threading_guard guard; + void load_state(lt::session& ses, entry const& st, boost::uint32_t flags) + { + allow_threading_guard guard; - std::vector buf; - bencode(std::back_inserter(buf), st); - bdecode_node e; - error_code ec; - bdecode(&buf[0], &buf[0] + buf.size(), e, ec); - TORRENT_ASSERT(!ec); - ses.load_state(e); - } + std::vector buf; + bencode(std::back_inserter(buf), st); + bdecode_node e; + error_code ec; + bdecode(&buf[0], &buf[0] + buf.size(), e, ec); + TORRENT_ASSERT(!ec); + ses.load_state(e, flags); + } #ifndef TORRENT_DISABLE_DHT void dht_get_mutable_item(lt::session& ses, std::string key, std::string salt) @@ -799,7 +799,7 @@ void bind_session() .def("get_pe_settings", allow_threads(<::session::get_pe_settings)) #endif #endif - .def("load_state", &load_state) + .def("load_state", &load_state, (arg("entry"), arg("flags") = 0xffffffff)) .def("save_state", &save_state, (arg("entry"), arg("flags") = 0xffffffff)) .def("pop_alerts", &pop_alerts) .def("wait_for_alert", &wait_for_alert @@ -888,8 +888,8 @@ void bind_session() .value("save_dht_settings", lt::session::save_dht_settings) .value("save_dht_state", lt::session::save_dht_state) .value("save_encryption_settings", lt::session:: save_encryption_settings) - .value("save_as_map", lt::session::save_as_map) #ifndef TORRENT_NO_DEPRECATE + .value("save_as_map", lt::session::save_as_map) .value("save_i2p_proxy", lt::session::save_i2p_proxy) .value("save_proxy", lt::session::save_proxy) .value("save_dht_proxy", lt::session::save_dht_proxy) diff --git a/examples/client_test.cpp b/examples/client_test.cpp index cfff11bb1..90a403b10 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -1576,6 +1576,9 @@ int main(int argc, char* argv[]) } ses.set_ip_filter(loaded_ip_filter); + ses.set_load_function(&load_torrent); + + error_code ec; #ifndef TORRENT_DISABLE_DHT dht_settings dht; @@ -1593,18 +1596,15 @@ int main(int argc, char* argv[]) ses.add_dht_router(std::make_pair( std::string("router.bitcomet.com"), 6881)); } -#endif - - ses.set_load_function(&load_torrent); std::vector in; - error_code ec; if (load_file(".ses_state", in, ec) == 0) { bdecode_node e; if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0) - ses.load_state(e); + ses.load_state(e, session::save_dht_state); } +#endif for (std::vector::iterator i = magnet_links.begin() , end(magnet_links.end()); i != end; ++i) @@ -2348,15 +2348,19 @@ int main(int argc, char* argv[]) } if (g_log_file) fclose(g_log_file); + + // we're just saving the DHT state +#ifndef TORRENT_DISABLE_DHT printf("\nsaving session state\n"); { entry session_state; - ses.save_state(session_state); + ses.save_state(session_state, session::save_dht_state); std::vector out; bencode(std::back_inserter(out), session_state); save_file(".ses_state", out); } +#endif printf("closing session"); diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index c155301fb..76d30ffb3 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -495,7 +495,7 @@ namespace libtorrent void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false) TORRENT_OVERRIDE; void save_state(entry* e, boost::uint32_t flags) const; - void load_state(bdecode_node const* e); + void load_state(bdecode_node const* e, boost::uint32_t flags); bool has_connection(peer_connection* p) const TORRENT_OVERRIDE; void insert_peer(boost::shared_ptr const& c) TORRENT_OVERRIDE; diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index f16ca0814..effb8f78f 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -229,7 +229,7 @@ namespace libtorrent // The const version of ``operator[]`` will only return a reference to an // existing element at the given key. If the key is not found, it will // throw ``libtorrent::type_error``. - entry& operator[](char const* key); + entry& operator[](char const* key); entry& operator[](std::string const& key); #ifndef BOOST_NO_EXCEPTIONS const entry& operator[](char const* key) const; diff --git a/include/libtorrent/session_handle.hpp b/include/libtorrent/session_handle.hpp index bd5f816a7..d387d4c9f 100644 --- a/include/libtorrent/session_handle.hpp +++ b/include/libtorrent/session_handle.hpp @@ -92,13 +92,11 @@ namespace libtorrent save_dht_state = 0x004, // save pe_settings - save_encryption_settings = 0x020, - - // internal - save_as_map = 0x040 + save_encryption_settings = 0x020 #ifndef TORRENT_NO_DEPRECATE , + save_as_map = 0x040, // saves RSS feeds save_feeds = 0x080, save_proxy = 0x008, @@ -118,11 +116,11 @@ namespace libtorrent // ``load_state`` expects a bdecode_node which can be built from a bencoded // buffer with bdecode(). // - // The ``flags`` arguments passed in to ``save_state`` can be used to - // filter which parts of the session state to save. By default, all state - // is saved (except for the individual torrents). see save_state_flags_t + // The ``flags`` argument is used to filter which parts of the session + // state to save or load. By default, all state is saved/restored (except + // for the individual torrents). see save_state_flags_t void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const; - void load_state(bdecode_node const& e); + void load_state(bdecode_node const& e, boost::uint32_t flags = 0xffffffff); // .. note:: // these calls are potentially expensive and won't scale well with @@ -547,12 +545,14 @@ namespace libtorrent // deprecated in 0.15 // use load_state and save_state instead TORRENT_DEPRECATED - void load_state(entry const& ses_state); + void load_state(entry const& ses_state + , boost::uint32_t flags = 0xffffffff); TORRENT_DEPRECATED entry state() const; // deprecated in 1.1 TORRENT_DEPRECATED - void load_state(lazy_entry const& ses_state); + void load_state(lazy_entry const& ses_state + , boost::uint32_t flags = 0xffffffff); #endif // TORRENT_NO_DEPRECATE // Sets a filter that will be used to reject and accept incoming as well diff --git a/src/session_handle.cpp b/src/session_handle.cpp index cf359759b..f6d656f70 100644 --- a/src/session_handle.cpp +++ b/src/session_handle.cpp @@ -102,11 +102,12 @@ namespace libtorrent TORRENT_SYNC_CALL2(save_state, &e, flags); } - void session_handle::load_state(bdecode_node const& e) + void session_handle::load_state(bdecode_node const& e + , boost::uint32_t const flags) { // this needs to be synchronized since the lifespan // of e is tied to the caller - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } void session_handle::get_torrent_status(std::vector* ret @@ -505,7 +506,8 @@ namespace libtorrent void session_handle::load_country_db(wchar_t const*) {} #endif // TORRENT_USE_WSTRING - void session_handle::load_state(entry const& ses_state) + void session_handle::load_state(entry const& ses_state + , boost::uint32_t const flags) { if (ses_state.type() == entry::undefined_t) return; std::vector buf; @@ -521,7 +523,7 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS if (ret != 0) throw libtorrent_exception(ec); #endif - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } entry session_handle::state() const @@ -531,7 +533,8 @@ namespace libtorrent return ret; } - void session_handle::load_state(lazy_entry const& ses_state) + void session_handle::load_state(lazy_entry const& ses_state + , boost::uint32_t const flags) { if (ses_state.type() == lazy_entry::none_t) return; std::pair buf = ses_state.data_section(); @@ -546,7 +549,7 @@ namespace libtorrent #ifndef BOOST_NO_EXCEPTIONS if (ret != 0) throw libtorrent_exception(ec); #endif - TORRENT_SYNC_CALL1(load_state, &e); + TORRENT_SYNC_CALL2(load_state, &e, flags); } #endif // TORRENT_NO_DEPRECATE diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 82a0477a9..510f0fb66 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -698,12 +698,16 @@ namespace aux { void session_impl::save_state(entry* eptr, boost::uint32_t flags) const { TORRENT_ASSERT(is_single_thread()); - TORRENT_UNUSED(flags); // potentially unused entry& e = *eptr; + // make it a dict + e.dict(); - entry::dictionary_type& sett = e["settings"].dict(); - save_settings_to_dict(m_settings, sett); + if (flags & session::save_settings) + { + entry::dictionary_type& sett = e["settings"].dict(); + save_settings_to_dict(m_settings, sett); + } #ifndef TORRENT_DISABLE_DHT if (flags & session::save_dht_settings) @@ -765,7 +769,8 @@ namespace aux { return proxy_settings(m_settings); } - void session_impl::load_state(bdecode_node const* e) + void session_impl::load_state(bdecode_node const* e + , boost::uint32_t const flags = 0xffffffff) { TORRENT_ASSERT(is_single_thread()); @@ -775,77 +780,86 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT bool need_update_dht = false; // load from the old settings names - settings = e->dict_find_dict("dht"); - if (settings) + if (flags & session::save_dht_settings) { - bdecode_node val; - val = settings.dict_find_int("max_peers_reply"); - if (val) m_dht_settings.max_peers_reply = val.int_value(); - val = settings.dict_find_int("search_branching"); - if (val) m_dht_settings.search_branching = val.int_value(); - val = settings.dict_find_int("max_fail_count"); - if (val) m_dht_settings.max_fail_count = val.int_value(); - val = settings.dict_find_int("max_torrents"); - if (val) m_dht_settings.max_torrents = val.int_value(); - val = settings.dict_find_int("max_dht_items"); - if (val) m_dht_settings.max_dht_items = val.int_value(); - val = settings.dict_find_int("max_peers"); - if (val) m_dht_settings.max_peers = val.int_value(); - val = settings.dict_find_int("max_torrent_search_reply"); - if (val) m_dht_settings.max_torrent_search_reply = val.int_value(); - val = settings.dict_find_int("restrict_routing_ips"); - if (val) m_dht_settings.restrict_routing_ips = val.int_value(); - val = settings.dict_find_int("restrict_search_ips"); - if (val) m_dht_settings.restrict_search_ips = val.int_value(); - val = settings.dict_find_int("extended_routing_table"); - if (val) m_dht_settings.extended_routing_table = val.int_value(); - val = settings.dict_find_int("aggressive_lookups"); - if (val) m_dht_settings.aggressive_lookups = val.int_value(); - val = settings.dict_find_int("privacy_lookups"); - if (val) m_dht_settings.privacy_lookups = val.int_value(); - val = settings.dict_find_int("enforce_node_id"); - if (val) m_dht_settings.enforce_node_id = val.int_value(); - val = settings.dict_find_int("ignore_dark_internet"); - if (val) m_dht_settings.ignore_dark_internet = val.int_value(); - val = settings.dict_find_int("block_timeout"); - if (val) m_dht_settings.block_timeout = val.int_value(); - val = settings.dict_find_int("block_ratelimit"); - if (val) m_dht_settings.block_ratelimit = val.int_value(); - val = settings.dict_find_int("read_only"); - if (val) m_dht_settings.read_only = val.int_value(); - val = settings.dict_find_int("item_lifetime"); - if (val) m_dht_settings.item_lifetime = val.int_value(); + settings = e->dict_find_dict("dht"); + if (settings) + { + bdecode_node val; + val = settings.dict_find_int("max_peers_reply"); + if (val) m_dht_settings.max_peers_reply = val.int_value(); + val = settings.dict_find_int("search_branching"); + if (val) m_dht_settings.search_branching = val.int_value(); + val = settings.dict_find_int("max_fail_count"); + if (val) m_dht_settings.max_fail_count = val.int_value(); + val = settings.dict_find_int("max_torrents"); + if (val) m_dht_settings.max_torrents = val.int_value(); + val = settings.dict_find_int("max_dht_items"); + if (val) m_dht_settings.max_dht_items = val.int_value(); + val = settings.dict_find_int("max_peers"); + if (val) m_dht_settings.max_peers = val.int_value(); + val = settings.dict_find_int("max_torrent_search_reply"); + if (val) m_dht_settings.max_torrent_search_reply = val.int_value(); + val = settings.dict_find_int("restrict_routing_ips"); + if (val) m_dht_settings.restrict_routing_ips = val.int_value(); + val = settings.dict_find_int("restrict_search_ips"); + if (val) m_dht_settings.restrict_search_ips = val.int_value(); + val = settings.dict_find_int("extended_routing_table"); + if (val) m_dht_settings.extended_routing_table = val.int_value(); + val = settings.dict_find_int("aggressive_lookups"); + if (val) m_dht_settings.aggressive_lookups = val.int_value(); + val = settings.dict_find_int("privacy_lookups"); + if (val) m_dht_settings.privacy_lookups = val.int_value(); + val = settings.dict_find_int("enforce_node_id"); + if (val) m_dht_settings.enforce_node_id = val.int_value(); + val = settings.dict_find_int("ignore_dark_internet"); + if (val) m_dht_settings.ignore_dark_internet = val.int_value(); + val = settings.dict_find_int("block_timeout"); + if (val) m_dht_settings.block_timeout = val.int_value(); + val = settings.dict_find_int("block_ratelimit"); + if (val) m_dht_settings.block_ratelimit = val.int_value(); + val = settings.dict_find_int("read_only"); + if (val) m_dht_settings.read_only = val.int_value(); + val = settings.dict_find_int("item_lifetime"); + if (val) m_dht_settings.item_lifetime = val.int_value(); + } } - settings = e->dict_find_dict("dht state"); - if (settings) + if (flags & session::save_dht_state) { - m_dht_state = settings; - need_update_dht = true; + settings = e->dict_find_dict("dht state"); + if (settings) + { + m_dht_state = settings; + need_update_dht = true; + } } #endif #ifndef TORRENT_NO_DEPRECATE bool need_update_proxy = false; - settings = e->dict_find_dict("proxy"); - if (settings) + if (flags & session::save_proxy) { - bdecode_node val; - val = settings.dict_find_int("port"); - if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value()); - val = settings.dict_find_int("type"); - if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value()); - val = settings.dict_find_int("proxy_hostnames"); - if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value()); - val = settings.dict_find_int("proxy_peer_connections"); - if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value()); - val = settings.dict_find_string("hostname"); - if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value()); - val = settings.dict_find_string("password"); - if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value()); - val = settings.dict_find_string("username"); - if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value()); - need_update_proxy = true; + settings = e->dict_find_dict("proxy"); + if (settings) + { + bdecode_node val; + val = settings.dict_find_int("port"); + if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value()); + val = settings.dict_find_int("type"); + if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value()); + val = settings.dict_find_int("proxy_hostnames"); + if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value()); + val = settings.dict_find_int("proxy_peer_connections"); + if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value()); + val = settings.dict_find_string("hostname"); + if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value()); + val = settings.dict_find_string("password"); + if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value()); + val = settings.dict_find_string("username"); + if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value()); + need_update_proxy = true; + } } settings = e->dict_find_dict("encryption"); @@ -862,39 +876,49 @@ namespace aux { if (val) m_settings.set_int(settings_pack::allowed_enc_level, val.int_value()); } - settings = e->dict_find_list("feeds"); - if (settings) + if (flags & session::save_feeds) { - m_feeds.reserve(settings.list_size()); - for (int i = 0; i < settings.list_size(); ++i) + settings = e->dict_find_list("feeds"); + if (settings) { - if (settings.list_at(i).type() != bdecode_node::dict_t) continue; - boost::shared_ptr f(new_feed(*this, feed_settings())); - f->load_state(settings.list_at(i)); - f->update_feed(); - m_feeds.push_back(f); + m_feeds.reserve(settings.list_size()); + for (int i = 0; i < settings.list_size(); ++i) + { + if (settings.list_at(i).type() != bdecode_node::dict_t) continue; + boost::shared_ptr f(new_feed(*this, feed_settings())); + f->load_state(settings.list_at(i)); + f->update_feed(); + m_feeds.push_back(f); + } + update_rss_feeds(); } - update_rss_feeds(); } #endif - settings = e->dict_find_dict("settings"); - if (settings) - { - // apply_settings_pack will update dht and proxy - boost::shared_ptr pack = load_pack_from_dict(settings); - apply_settings_pack(pack); - } - else + if (flags & session::save_settings) { + settings = e->dict_find_dict("settings"); + if (settings) + { + // apply_settings_pack will update dht and proxy + boost::shared_ptr pack = load_pack_from_dict(settings); + apply_settings_pack(pack); #ifndef TORRENT_DISABLE_DHT - if (need_update_dht) update_dht(); + need_update_dht = false; #endif #ifndef TORRENT_NO_DEPRECATE - if (need_update_proxy) update_proxy(); + need_update_proxy = false; #endif + } } +#ifndef TORRENT_DISABLE_DHT + if (need_update_dht) update_dht(); +#endif +#ifndef TORRENT_NO_DEPRECATE + if (need_update_proxy) update_proxy(); +#endif + #ifndef TORRENT_DISABLE_EXTENSIONS for (ses_extension_list_t::iterator i = m_ses_extensions.begin() , end(m_ses_extensions.end()); i != end; ++i) diff --git a/test/test_session.cpp b/test/test_session.cpp index 7b30365bc..2c6e4d745 100644 --- a/test/test_session.cpp +++ b/test/test_session.cpp @@ -38,6 +38,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/session_stats.hpp" #include "libtorrent/performance_counters.hpp" +#include "libtorrent/bdecode.hpp" +#include "libtorrent/bencode.hpp" using namespace libtorrent; namespace lt = libtorrent; @@ -105,4 +107,107 @@ TORRENT_TEST(session_stats) TEST_EQUAL(stats[i].value_index, i); } } +#if __cplusplus >= 201103L + +template +void test_save_restore(Set setup, Save s, Default d, Load l) +{ + entry st; + { + settings_pack p; + setup(p); + lt::session ses(p); + s(ses, st); + } + + { + settings_pack p; + d(p); + lt::session ses(p); + // the loading function takes a bdecode_node, so we have to transform the + // entry + printf("%s\n", st.to_string().c_str()); + std::vector buf; + bencode(std::back_inserter(buf), st); + bdecode_node state; + error_code ec; + int ret = bdecode(buf.data(), buf.data() + buf.size() + , state, ec, nullptr, 100, 1000); + TEST_EQUAL(ret, 0); + if (ec) + { + printf("bdecode: %s\n", ec.message().c_str()); + printf("%s\n", std::string(buf.data(), buf.size()).c_str()); + } + TEST_CHECK(!ec); + l(ses, state); + } +} + +TORRENT_TEST(save_restore_state) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + ses.save_state(st); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + ses.load_state(st); + // make sure we loaded the cache size correctly + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 1337); + }); +} + +TORRENT_TEST(save_restore_state_save_filter) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + // save everything _but_ the settings + ses.save_state(st, ~session::save_settings); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + ses.load_state(st); + // make sure whatever we loaded did not include the cache size + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90); + }); +} + +TORRENT_TEST(save_restore_state_load_filter) +{ + test_save_restore( + [](settings_pack& p) { + // set the cache size + p.set_int(settings_pack::cache_size, 1337); + }, + [](lt::session& ses, entry& st) { + // save everything + ses.save_state(st); + }, + [](settings_pack& p) { + p.set_int(settings_pack::cache_size, 90); + }, + [](lt::session& ses, bdecode_node& st) { + // load everything _but_ the settings + ses.load_state(st, ~session::save_settings); + settings_pack sett = ses.get_settings(); + TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90); + }); +} + +#endif From f5d5ac4f3a64493798001e2aa43cac1699a5bd16 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 6 Mar 2016 21:42:18 -0500 Subject: [PATCH 28/29] fix bug where disk cache was wiped out after completion file-checking. factor out sim test utilities and reuse them in the regression test --- include/libtorrent/torrent.hpp | 10 ++- simulation/Jamfile | 2 + simulation/test_checking.cpp | 115 +++++++++++++++++++++++++++ simulation/test_transfer.cpp | 116 ++------------------------- simulation/utils.cpp | 139 +++++++++++++++++++++++++++++++++ simulation/utils.hpp | 60 ++++++++++++++ src/session_impl.cpp | 3 +- src/torrent.cpp | 23 +++--- test/test_checking.cpp | 2 +- 9 files changed, 347 insertions(+), 123 deletions(-) create mode 100644 simulation/test_checking.cpp create mode 100644 simulation/utils.cpp create mode 100644 simulation/utils.hpp diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 68e9493b7..48c5e6c08 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -459,7 +459,13 @@ namespace libtorrent void flush_cache(); void pause(bool graceful = false); void resume(); - void set_allow_peers(bool b, bool graceful_pause = false); + + enum pause_flags_t + { + flag_graceful_pause = 1, + flag_clear_disk_cache = 2 + }; + void set_allow_peers(bool b, int flags = flag_clear_disk_cache); void set_announce_to_dht(bool b) { m_announce_to_dht = b; } void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; } void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; } @@ -468,7 +474,7 @@ namespace libtorrent int started() const { return m_started; } void step_session_time(int seconds); - void do_pause(); + void do_pause(bool clear_disk_cache = true); void do_resume(); int finished_time() const; diff --git a/simulation/Jamfile b/simulation/Jamfile index 4e99da0f9..5a32e0da7 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -15,6 +15,7 @@ project setup_swarm.cpp setup_dht.cpp create_torrent.cpp + utils.cpp : default-build multi full @@ -23,6 +24,7 @@ project ; alias libtorrent-sims : + [ run test_checking.cpp ] [ run test_optimistic_unchoke.cpp ] [ run test_transfer.cpp ] [ run test_http_connection.cpp ] diff --git a/simulation/test_checking.cpp b/simulation/test_checking.cpp new file mode 100644 index 000000000..87d27a3ca --- /dev/null +++ b/simulation/test_checking.cpp @@ -0,0 +1,115 @@ +/* + +Copyright (c) 2016, 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/deadline_timer.hpp" +#include "libtorrent/address.hpp" +#include "libtorrent/torrent_status.hpp" +#include "simulator/simulator.hpp" + +#include "test.hpp" +#include "settings.hpp" +#include "create_torrent.hpp" +#include "utils.hpp" + +template +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::unique_ptr(new sim::asio::io_service( + sim, lt::address_v4::from_string("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(pack, *ios); + + ses->async_add_torrent(atp); + + print_alerts(*ses); + + lt::deadline_timer timer(*ios); + timer.expires_from_now(lt::seconds(6)); + timer.async_wait([&](lt::error_code const& ec) + { + test(*ses); + + // shut down + ses->set_alert_notify([]{}); + zombie = ses->abort(); + ses.reset(); + }); + + sim.run(); +} + +TORRENT_TEST(cache_after_checking) +{ + run_test( + [](lt::add_torrent_params& atp, lt::settings_pack& p) { + atp.flags |= lt::add_torrent_params::flag_auto_managed; + p.set_int(lt::settings_pack::cache_size, 100); + }, + [](lt::session& ses) { + int cache = get_cache_size(ses); + TEST_CHECK(cache > 0); + + std::vector tor = ses.get_torrents(); + TEST_EQUAL(tor.size(), 1); + + TEST_EQUAL(tor[0].status().is_seeding, true); + }); +} + +TORRENT_TEST(checking_no_cache) +{ + run_test( + [](lt::add_torrent_params& atp, lt::settings_pack& p) { + atp.flags |= lt::add_torrent_params::flag_auto_managed; + p.set_int(lt::settings_pack::cache_size, 0); + }, + [](lt::session& ses) { + int cache = get_cache_size(ses); + TEST_EQUAL(cache, 0); + + std::vector tor = ses.get_torrents(); + TEST_EQUAL(tor.size(), 1); + + TEST_EQUAL(tor[0].status().is_seeding, true); + }); +} diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index ddae108ba..07f948dcb 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -45,16 +45,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "simulator/simulator.hpp" #include "simulator/socks_server.hpp" #include "setup_swarm.hpp" +#include "utils.hpp" using namespace sim; namespace lt = libtorrent; -enum flags_t -{ - ipv6 = 1, -}; - template void run_test( Setup const& setup @@ -64,8 +60,6 @@ void run_test( { using namespace libtorrent; - lt::time_point start_time = lt::clock_type::now(); - const bool use_ipv6 = flags & ipv6; char const* peer0_ip[2] = { "50.0.0.1", "feed:face:baad:f00d::1" }; @@ -113,32 +107,15 @@ void run_test( setup(*ses[0], *ses[1]); // only monitor alerts for session 0 (the downloader) - ses[0]->set_alert_notify([&] { ios0.post([&] { - std::vector alerts; - ses[0]->pop_alerts(&alerts); - - for (lt::alert const* a : alerts) + print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) { + if (auto ta = alert_cast(a)) { - printf("%-3d [0] %s\n", int(lt::duration_cast(a->timestamp() - - start_time).count()), a->message().c_str()); - if (auto ta = alert_cast(a)) - { - ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); - } - // call the user handler - on_alert(*ses[0], a); + ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); } - } ); } ); + on_alert(ses, a); + }); - ses[1]->set_alert_notify([&] { ios0.post([&] { - std::vector alerts; - ses[1]->pop_alerts(&alerts); - for (lt::alert const* a : alerts) - { - printf("%-3d [1] %s\n", int(lt::duration_cast(a->timestamp() - - start_time).count()), a->message().c_str()); - } - } ); } ); + print_alerts(*ses[1]); // the first peer is a downloader, the second peer is a seed lt::add_torrent_params params = create_torrent(1); @@ -170,85 +147,6 @@ void run_test( sim.run(); } -void utp_only(lt::session& ses) -{ - using namespace libtorrent; - settings_pack p; - utp_only(p); - ses.apply_settings(p); -} - -void enable_enc(lt::session& ses) -{ - using namespace libtorrent; - settings_pack p; - enable_enc(p); - ses.apply_settings(p); -} - -void filter_ips(lt::session& ses) -{ - using namespace libtorrent; - ip_filter filter; - filter.add_rule(asio::ip::address_v4::from_string("50.0.0.1") - , asio::ip::address_v4::from_string("50.0.0.2"), ip_filter::blocked); - ses.set_ip_filter(filter); -} - -void set_cache_size(lt::session& ses, int val) -{ - using namespace libtorrent; - settings_pack pack; - pack.set_int(settings_pack::cache_size, val); - ses.apply_settings(pack); -} - -int get_cache_size(lt::session& ses) -{ - using namespace libtorrent; - std::vector stats = session_stats_metrics(); - int const read_cache_idx = find_metric_idx("disk.read_cache_blocks"); - int const write_cache_idx = find_metric_idx("disk.write_cache_blocks"); - TEST_CHECK(read_cache_idx >= 0); - TEST_CHECK(write_cache_idx >= 0); - ses.set_alert_notify([](){}); - ses.post_session_stats(); - std::vector alerts; - ses.pop_alerts(&alerts); - int cache_size = -1; - for (auto const a : alerts) - { - if (auto const* st = alert_cast(a)) - { - cache_size = st->values[read_cache_idx]; - cache_size += st->values[write_cache_idx]; - break; - } - } - return cache_size; -} - -void set_proxy(lt::session& ses, int proxy_type, int flags = 0, bool proxy_peer_connections = true) -{ - // apply the proxy settings to session 0 - using namespace libtorrent; - settings_pack p; - p.set_int(settings_pack::proxy_type, proxy_type); - if (proxy_type == settings_pack::socks4) - p.set_int(settings_pack::proxy_port, 4444); - else - p.set_int(settings_pack::proxy_port, 5555); - if (flags & ipv6) - p.set_str(settings_pack::proxy_hostname, "2001::2"); - else - p.set_str(settings_pack::proxy_hostname, "50.50.50.50"); - p.set_bool(settings_pack::proxy_hostnames, true); - p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections); - p.set_bool(settings_pack::proxy_tracker_connections, true); - - ses.apply_settings(p); -} - TORRENT_TEST(socks4_tcp) { using namespace libtorrent; diff --git a/simulation/utils.cpp b/simulation/utils.cpp new file mode 100644 index 000000000..e8d007205 --- /dev/null +++ b/simulation/utils.cpp @@ -0,0 +1,139 @@ +/* + +Copyright (c) 2016, 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 "utils.hpp" +#include "test.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/settings_pack.hpp" +#include "libtorrent/address.hpp" +#include "libtorrent/ip_filter.hpp" +#include "libtorrent/alert_types.hpp" +#include "libtorrent/session_stats.hpp" +#include "libtorrent/alert.hpp" +#include "setup_swarm.hpp" + +using namespace libtorrent; + +void utp_only(lt::session& ses) +{ + settings_pack p; + utp_only(p); + ses.apply_settings(p); +} + +void enable_enc(lt::session& ses) +{ + settings_pack p; + enable_enc(p); + ses.apply_settings(p); +} + +void filter_ips(lt::session& ses) +{ + ip_filter filter; + filter.add_rule(address_v4::from_string("50.0.0.1") + , address_v4::from_string("50.0.0.2"), ip_filter::blocked); + ses.set_ip_filter(filter); +} + +void set_cache_size(lt::session& ses, int val) +{ + settings_pack pack; + pack.set_int(settings_pack::cache_size, val); + ses.apply_settings(pack); +} + +int get_cache_size(lt::session& ses) +{ + std::vector stats = session_stats_metrics(); + int const read_cache_idx = find_metric_idx("disk.read_cache_blocks"); + int const write_cache_idx = find_metric_idx("disk.write_cache_blocks"); + TEST_CHECK(read_cache_idx >= 0); + TEST_CHECK(write_cache_idx >= 0); + ses.set_alert_notify([](){}); + ses.post_session_stats(); + std::vector alerts; + ses.pop_alerts(&alerts); + int cache_size = -1; + for (auto const a : alerts) + { + if (auto const* st = alert_cast(a)) + { + cache_size = st->values[read_cache_idx]; + cache_size += st->values[write_cache_idx]; + break; + } + } + return cache_size; +} + +void set_proxy(lt::session& ses, int proxy_type, int flags, bool proxy_peer_connections) +{ + // apply the proxy settings to session 0 + settings_pack p; + p.set_int(settings_pack::proxy_type, proxy_type); + if (proxy_type == settings_pack::socks4) + p.set_int(settings_pack::proxy_port, 4444); + else + p.set_int(settings_pack::proxy_port, 5555); + if (flags & ipv6) + p.set_str(settings_pack::proxy_hostname, "2001::2"); + else + p.set_str(settings_pack::proxy_hostname, "50.50.50.50"); + p.set_bool(settings_pack::proxy_hostnames, true); + p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections); + p.set_bool(settings_pack::proxy_tracker_connections, true); + + ses.apply_settings(p); +} + +void print_alerts(lt::session& ses + , std::function on_alert) +{ + lt::time_point start_time = lt::clock_type::now(); + + ses.set_alert_notify([&ses,start_time,on_alert] { + ses.get_io_service().post([&ses,start_time,on_alert] { + + std::vector alerts; + ses.pop_alerts(&alerts); + + for (lt::alert const* a : alerts) + { + printf("%-3d [0] %s\n", int(lt::duration_cast(a->timestamp() + - start_time).count()), a->message().c_str()); + // call the user handler + on_alert(ses, a); + } + } ); } ); +} + diff --git a/simulation/utils.hpp b/simulation/utils.hpp new file mode 100644 index 000000000..26cfbf96e --- /dev/null +++ b/simulation/utils.hpp @@ -0,0 +1,60 @@ +/* + +Copyright (c) 2016, 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 + +namespace libtorrent +{ + class session; + class alert; +} + +namespace lt = libtorrent; + +void utp_only(lt::session& ses); +void enable_enc(lt::session& ses); +void filter_ips(lt::session& ses); +void set_cache_size(lt::session& ses, int val); +int get_cache_size(lt::session& ses); + +enum flags_t +{ + ipv6 = 1, +}; + +void set_proxy(lt::session& ses, int proxy_type, int flags = 0 + , bool proxy_peer_connections = true); + +void print_alerts(lt::session& ses + , std::function on_alert + = [](lt::session& ses, lt::alert const* a) {}); + diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 510f0fb66..b38567f83 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -3741,7 +3741,8 @@ retry: t->log_to_all_peers("auto manager pausing torrent"); #endif // use graceful pause for auto-managed torrents - t->set_allow_peers(false, true); + t->set_allow_peers(false, torrent::flag_graceful_pause + | torrent::flag_clear_disk_cache); t->set_announce_to_dht(false); t->set_announce_to_trackers(false); t->set_announce_to_lsd(false); diff --git a/src/torrent.cpp b/src/torrent.cpp index b9c99794c..7b11f071f 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2879,7 +2879,9 @@ namespace libtorrent { // if we're auto managed. assume we need to be paused until the auto // managed logic runs again (which is triggered further down) - pause(); + // setting flags to 0 prevents the disk cache from being evicted as a + // result of this + set_allow_peers(false, 0); } // we're done checking! (this should cause a call to trigger_auto_manage) @@ -9706,10 +9708,11 @@ namespace libtorrent set_need_save_resume(); } - set_allow_peers(false, graceful); + int const flags = graceful ? flag_graceful_pause : 0; + set_allow_peers(false, flags | flag_clear_disk_cache); } - void torrent::do_pause() + void torrent::do_pause(bool const clear_disk_cache) { TORRENT_ASSERT(is_single_thread()); if (!is_paused()) return; @@ -9773,7 +9776,7 @@ namespace libtorrent { // this will make the storage close all // files and flush all cached data - if (m_storage.get()) + if (m_storage.get() && clear_disk_cache) { TORRENT_ASSERT(m_storage); m_ses.disk_thread().async_stop_torrent(m_storage.get() @@ -9873,7 +9876,7 @@ namespace libtorrent set_need_save_resume(); } - void torrent::set_allow_peers(bool b, bool graceful) + void torrent::set_allow_peers(bool b, int flags) { TORRENT_ASSERT(is_single_thread()); @@ -9883,7 +9886,7 @@ namespace libtorrent // if there are no peers, we must not enter graceful pause mode, and post // the torrent_paused_alert immediately instead. if (m_connections.empty()) - graceful = false; + flags &= ~flag_graceful_pause; if (m_allow_peers == b) { @@ -9892,9 +9895,9 @@ namespace libtorrent // paused mode, we need to actually pause the torrent properly if (m_allow_peers == false && m_graceful_pause_mode == true - && graceful == false) + && (flags & flag_graceful_pause) == 0) { - m_graceful_pause_mode = graceful; + m_graceful_pause_mode = false; update_gauge(); do_pause(); } @@ -9903,7 +9906,7 @@ namespace libtorrent m_allow_peers = b; if (!m_ses.is_paused()) - m_graceful_pause_mode = graceful; + m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false; if (!b) { @@ -9920,7 +9923,7 @@ namespace libtorrent if (!b) { - do_pause(); + do_pause(flags & flag_clear_disk_cache); } else { diff --git a/test/test_checking.cpp b/test/test_checking.cpp index d19386a9d..f78f3b04b 100644 --- a/test/test_checking.cpp +++ b/test/test_checking.cpp @@ -94,7 +94,7 @@ void test_checking(int flags = read_only_files) create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec); if (ec) fprintf(stderr, "ERROR: creating directory test_torrent_dir: (%d) %s\n" , ec.value(), ec.message().c_str()); - + file_storage fs; std::srand(10); int piece_size = 0x4000; From 71e3fb8941ddeaa6af0cc833e51e8149f475990d Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 7 Mar 2016 23:40:01 -0500 Subject: [PATCH 29/29] fix division by zero in super-seeding logic --- ChangeLog | 2 ++ src/torrent.cpp | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index e5db9c4ba..798542c40 100644 --- a/ChangeLog +++ b/ChangeLog @@ -86,6 +86,8 @@ * almost completely changed the storage interface (for custom storage) * added support for hashing pieces in multiple threads + * fix division by zero in super-seeding logic + 1.0.9 release * fix issue in checking outgoing interfaces (when that option is enabled) diff --git a/src/torrent.cpp b/src/torrent.cpp index 7b11f071f..ea9a1638c 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -5002,6 +5002,9 @@ namespace libtorrent // seeded by any peer TORRENT_ASSERT(m_super_seeding); + if (!need_loaded()) + return -1; + // do a linear search from the first piece int min_availability = 9999; std::vector avail_vec; @@ -5034,6 +5037,7 @@ namespace libtorrent avail_vec.push_back(i); } + if (avail_vec.empty()) return -1; return avail_vec[random() % avail_vec.size()]; }