From c966435d1c3a9afbe12a069f82225de01f18f744 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Mon, 10 Oct 2016 22:54:19 -0400 Subject: [PATCH 1/9] fix issue where shutting down the session immediately and asynchronously starting the DHT would cause a shutdown hang (#1203) --- src/session_impl.cpp | 2 ++ test/test_session.cpp | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index dc1474f67..d24af11e8 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -5805,6 +5805,8 @@ retry: // postpone starting the DHT if we're still resolving the DHT router if (m_outstanding_router_lookups > 0) return; + if (m_abort) return; + m_dht = boost::make_shared(static_cast(this) , boost::ref(m_udp_socket), boost::cref(m_dht_settings) , boost::ref(m_stats_counters) diff --git a/test/test_session.cpp b/test/test_session.cpp index fec541ad0..573eea1e4 100644 --- a/test/test_session.cpp +++ b/test/test_session.cpp @@ -256,5 +256,11 @@ TORRENT_TEST(save_restore_state_load_filter) }); } +TORRENT_TEST(session_shutdown) +{ + lt::settings_pack pack; + lt::session ses(pack); +} + #endif From 25195a72602f6dce7b275c58bb4f55bd37c0f240 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Fri, 14 Oct 2016 23:47:59 -0400 Subject: [PATCH 2/9] back port DHT fixes from master (#1209) back port DHT fixes from master --- .../kademlia/traversal_algorithm.hpp | 8 ++++---- src/kademlia/get_item.cpp | 6 +----- src/kademlia/get_peers.cpp | 6 +----- src/kademlia/put_data.cpp | 6 +----- src/kademlia/traversal_algorithm.cpp | 20 ++++++++++++++----- 5 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/libtorrent/kademlia/traversal_algorithm.hpp b/include/libtorrent/kademlia/traversal_algorithm.hpp index d04828619..a541083e0 100644 --- a/include/libtorrent/kademlia/traversal_algorithm.hpp +++ b/include/libtorrent/kademlia/traversal_algorithm.hpp @@ -117,10 +117,10 @@ protected: std::vector m_results; node_id const m_target; boost::uint16_t m_ref_count; - boost::uint16_t m_invoke_count; - boost::uint16_t m_branch_factor; - boost::uint16_t m_responses; - boost::uint16_t m_timeouts; + boost::int16_t m_invoke_count; + boost::int16_t m_branch_factor; + boost::int16_t m_responses; + boost::int16_t m_timeouts; // the IP addresses of the nodes in m_results std::set m_peer4_prefixes; diff --git a/src/kademlia/get_item.cpp b/src/kademlia/get_item.cpp index 61c9bd3c4..aef3a6df1 100644 --- a/src/kademlia/get_item.cpp +++ b/src/kademlia/get_item.cpp @@ -141,11 +141,7 @@ observer_ptr get_item::new_observer(void* ptr bool get_item::invoke(observer_ptr o) { - if (m_done) - { - m_invoke_count = -1; - return false; - } + if (m_done) return false; entry e; e["y"] = "q"; diff --git a/src/kademlia/get_peers.cpp b/src/kademlia/get_peers.cpp index 05a72375d..6645f197f 100644 --- a/src/kademlia/get_peers.cpp +++ b/src/kademlia/get_peers.cpp @@ -134,11 +134,7 @@ char const* get_peers::name() const { return "get_peers"; } bool get_peers::invoke(observer_ptr o) { - if (m_done) - { - m_invoke_count = -1; - return false; - } + if (m_done) return false; entry e; e["y"] = "q"; diff --git a/src/kademlia/put_data.cpp b/src/kademlia/put_data.cpp index 393e3406a..85e321246 100644 --- a/src/kademlia/put_data.cpp +++ b/src/kademlia/put_data.cpp @@ -88,11 +88,7 @@ void put_data::done() bool put_data::invoke(observer_ptr o) { - if (m_done) - { - m_invoke_count = -1; - return false; - } + if (m_done) return false; // TODO: what if o is not an isntance of put_data_observer? This need to be // redesigned for better type saftey. diff --git a/src/kademlia/traversal_algorithm.cpp b/src/kademlia/traversal_algorithm.cpp index d7d380adb..6188966b8 100644 --- a/src/kademlia/traversal_algorithm.cpp +++ b/src/kademlia/traversal_algorithm.cpp @@ -319,6 +319,8 @@ void traversal_algorithm::failed(observer_ptr o, int flags) if (m_results.empty()) return; + bool decrement_branch_factor = false; + TORRENT_ASSERT(o->flags & observer::flag_queried); if (flags & short_timeout) { @@ -329,7 +331,10 @@ void traversal_algorithm::failed(observer_ptr o, int flags) // around for some more, but open up the slot // by increasing the branch factor if ((o->flags & observer::flag_short_timeout) == 0) + { + TORRENT_ASSERT(m_branch_factor < (std::numeric_limits::max)()); ++m_branch_factor; + } o->flags |= observer::flag_short_timeout; #ifndef TORRENT_DISABLE_LOGGING if (get_node().observer()) @@ -350,8 +355,7 @@ void traversal_algorithm::failed(observer_ptr o, int flags) o->flags |= observer::flag_failed; // if this flag is set, it means we increased the // branch factor for it, and we should restore it - if (o->flags & observer::flag_short_timeout) - --m_branch_factor; + decrement_branch_factor = (o->flags & observer::flag_short_timeout) != 0; #ifndef TORRENT_DISABLE_LOGGING if (get_node().observer()) @@ -372,12 +376,18 @@ void traversal_algorithm::failed(observer_ptr o, int flags) --m_invoke_count; } - if (flags & prevent_request) + // this is another reason to decrement the branch factor, to prevent another + // request from filling this slot. Only ever decrement once per response though + decrement_branch_factor |= (flags & prevent_request); + + if (decrement_branch_factor) { + TORRENT_ASSERT(m_branch_factor > 0); --m_branch_factor; if (m_branch_factor <= 0) m_branch_factor = 1; } - bool is_done = add_requests(); + + bool const is_done = add_requests(); if (is_done) done(); } @@ -499,7 +509,7 @@ bool traversal_algorithm::add_requests() o->flags |= observer::flag_queried; if (invoke(*i)) { - TORRENT_ASSERT(m_invoke_count < (std::numeric_limits::max)()); + TORRENT_ASSERT(m_invoke_count < (std::numeric_limits::max)()); ++m_invoke_count; ++outstanding; } From 344eedb969366e62c38c6968d9bb85f7bbe7b960 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 15 Oct 2016 21:29:01 -0400 Subject: [PATCH 3/9] add python scrape_tracker test --- bindings/python/test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bindings/python/test.py b/bindings/python/test.py index 4e5fa9afe..3d6ff5325 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -40,6 +40,14 @@ class test_torrent_handle(unittest.TestCase): h.prioritize_pieces([(0, 1)]) self.assertEqual(h.piece_priorities(), [1]) + def test_scrape(self): + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories, 'enable_dht': False}) + ti = lt.torrent_info('url_seed_multi.torrent'); + h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) + # this is just to make sure this function can be called like this + # from python + h.scrape_tracker() + class test_torrent_info(unittest.TestCase): def test_bencoded_constructor(self): From c13286b9454b6cd110e148b0c7c35e4ac1786be1 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Thu, 13 Oct 2016 19:19:03 -0700 Subject: [PATCH 4/9] take upload speed into account in round-robin choker The unchoked peers need to be sorted by upload speed so that the slowest node will get choked as part of optimistic unchoking. Also change the minimum quanta to 1 minute instead of 256KB. Also remove a useless multiply in the fastest peer choker since the priorities are guarenteed to be equal at that point. Fixes #1171 --- src/choker.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/choker.cpp b/src/choker.cpp index 783b00415..a3f022380 100644 --- a/src/choker.cpp +++ b/src/choker.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/choker.hpp" #include "libtorrent/peer_connection.hpp" #include "libtorrent/aux_/session_settings.hpp" +#include "libtorrent/aux_/time.hpp" #include "libtorrent/torrent.hpp" #include @@ -82,21 +83,30 @@ namespace libtorrent // if a peer is already unchoked, and the number of bytes sent since it was unchoked // is greater than the send quanta, then it's done with it' upload slot, and we // can de-prioritize it - bool c1_quota_complete = !lhs->is_choked() && c1 - > (std::max)(t1->torrent_file().piece_length() * pieces, 256 * 1024); - bool c2_quota_complete = !rhs->is_choked() && c2 - > (std::max)(t2->torrent_file().piece_length() * pieces, 256 * 1024); + bool c1_quota_complete = !lhs->is_choked() + && c1 > t1->torrent_file().piece_length() * pieces + && aux::time_now() - lhs->time_of_last_unchoke() > minutes(1); + bool c2_quota_complete = !rhs->is_choked() + && c2 > t2->torrent_file().piece_length() * pieces + && aux::time_now() - rhs->time_of_last_unchoke() > minutes(1); // if c2 has completed a quanta, it should be de-prioritized // and vice versa if (c1_quota_complete < c2_quota_complete) return true; if (c1_quota_complete > c2_quota_complete) return false; - // if both peers have either completed a quanta, or not. - // keep unchoked peers prioritized over choked ones, to let - // peers keep working on uploading a full quanta - if (lhs->is_choked() < rhs->is_choked()) return true; - if (lhs->is_choked() > rhs->is_choked()) return false; + // when seeding, prefer the peer we're uploading the fastest to + + // force the upload rate to zero for choked peers because + // if the peers just got choked the previous round + // there may have been a residual transfer which was already + // in-flight at the time and we don't want that to cause the peer + // to be ranked at the top of the choked peers + c1 = lhs->is_choked() ? 0 : lhs->uploaded_in_last_round(); + c2 = rhs->is_choked() ? 0 : rhs->uploaded_in_last_round(); + + if (c1 > c2) return true; + if (c2 > c1) return false; // if the peers are still identical (say, they're both waiting to be unchoked) // prioritize the one that has waited the longest to be unchoked @@ -134,10 +144,6 @@ namespace libtorrent 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; From fc7b4c1c4f01e1b3c77e46abb219b49fdca5dafc Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Sat, 15 Oct 2016 14:40:56 -0700 Subject: [PATCH 5/9] update comment to reflect new quota definition --- src/choker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/choker.cpp b/src/choker.cpp index a3f022380..edbc7044d 100644 --- a/src/choker.cpp +++ b/src/choker.cpp @@ -80,9 +80,9 @@ namespace libtorrent // peers that are unchoked, but have sent more than one quota // since they were unchoked, they get de-prioritized. - // if a peer is already unchoked, and the number of bytes sent since it was unchoked - // is greater than the send quanta, then it's done with it' upload slot, and we - // can de-prioritize it + // if a peer is already unchoked, the number of bytes sent since it was unchoked + // is greater than the send quanta, and it has been unchoked for at least one minute + // then it's done with its upload slot, and we can de-prioritize it bool c1_quota_complete = !lhs->is_choked() && c1 > t1->torrent_file().piece_length() * pieces && aux::time_now() - lhs->time_of_last_unchoke() > minutes(1); From 037f349cee023fbe056914a82a2ca6cdedd94964 Mon Sep 17 00:00:00 2001 From: Pavel Pimenov Date: Thu, 20 Oct 2016 00:29:35 +0300 Subject: [PATCH 6/9] Try resolve #1175 (for RC_1_1) (#1230) https://github.com/arvidn/libtorrent/pull/1223 --- include/libtorrent/upnp.hpp | 5 ++--- src/upnp.cpp | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index e4c7e73d0..beee17768 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -281,8 +281,7 @@ private: struct rootdevice { - rootdevice(): service_namespace(0) - , port(0) + rootdevice(): port(0) , lease_duration(default_lease_time) , supports_specific_external(true) , disabled(false) @@ -312,7 +311,7 @@ private: // the url to the WANIP or WANPPP interface std::string control_url; // either the WANIP namespace or the WANPPP namespace - char const* service_namespace; + std::string service_namespace; std::vector mapping; diff --git a/src/upnp.cpp b/src/upnp.cpp index 85f462322..ab10a02a2 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -211,7 +211,7 @@ int upnp::add_mapping(upnp::protocol_type p, int external_port, int local_port) m.external_port = external_port; m.local_port = local_port; - if (d.service_namespace) update_map(d, mapping_index, l); + if (!d.service_namespace.empty()) update_map(d, mapping_index, l); } return mapping_index; @@ -242,7 +242,7 @@ void upnp::delete_mapping(int mapping) TORRENT_ASSERT(mapping < int(d.mapping.size())); d.mapping[mapping].action = mapping_t::action_delete; - if (d.service_namespace) update_map(d, mapping, l); + if (!d.service_namespace.empty()) update_map(d, mapping, l); } } @@ -654,7 +654,7 @@ void upnp::post(upnp::rootdevice const& d, char const* soap "Soapaction: \"%s#%s\"\r\n\r\n" "%s" , d.path.c_str(), d.hostname.c_str(), d.port - , int(strlen(soap)), d.service_namespace, soap_action + , int(strlen(soap)), d.service_namespace.c_str(), soap_action , soap); d.upnp_connection->m_sendbuffer = header; @@ -698,7 +698,7 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) "%s at %s:%d" "%u" "" - , soap_action, d.service_namespace, d.mapping[i].external_port + , soap_action, d.service_namespace.c_str(), d.mapping[i].external_port , (d.mapping[i].protocol == udp ? "UDP" : "TCP") , d.mapping[i].local_port , local_endpoint.c_str() @@ -749,7 +749,7 @@ void upnp::update_map(rootdevice& d, int i, mutex::scoped_lock& l) } TORRENT_ASSERT(!d.upnp_connection); - TORRENT_ASSERT(d.service_namespace); + TORRENT_ASSERT(!d.service_namespace.empty()); char msg[500]; snprintf(msg, sizeof(msg), "connecting to %s", d.hostname.c_str()); @@ -816,7 +816,7 @@ void upnp::delete_port_mapping(rootdevice& d, int i) "%u" "%s" "" - , soap_action, d.service_namespace + , soap_action, d.service_namespace.c_str() , d.mapping[i].external_port , (d.mapping[i].protocol == udp ? "UDP" : "TCP") , soap_action); @@ -945,9 +945,10 @@ void upnp::on_upnp_xml(error_code const& e d.disabled = true; return; } - static std::string service_type; - service_type.swap(s.service_type); - d.service_namespace = service_type.c_str(); + d.service_namespace = s.service_type; + + TORRENT_ASSERT(!d.service_namespace.empty()); + if (!s.model.empty()) m_model = s.model; if (!s.url_base.empty() && s.control_url.substr(0, 7) != "http://") @@ -977,7 +978,7 @@ void upnp::on_upnp_xml(error_code const& e char msg[500]; snprintf(msg, sizeof(msg), "found control URL: %s namespace %s " "urlbase: %s in response from %s" - , d.control_url.c_str(), d.service_namespace + , d.control_url.c_str(), d.service_namespace.c_str() , s.url_base.c_str(), d.url.c_str()); log(msg, l); } @@ -1029,7 +1030,7 @@ void upnp::get_ip_address(rootdevice& d) "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "" "" - , soap_action, d.service_namespace + , soap_action, d.service_namespace.c_str() , soap_action); post(d, soap, soap_action, l); From 7009001f732a0d698763a97eba71a43e89ad57ea Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 20 Oct 2016 00:13:45 -0400 Subject: [PATCH 7/9] fix ambiguous call to abs() in tommath (#1228) fix ambiguous call to abs() in tommath --- src/mpi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mpi.cpp b/src/mpi.cpp index b8104f88e..ef0865b52 100644 --- a/src/mpi.cpp +++ b/src/mpi.cpp @@ -6708,7 +6708,7 @@ mp_rand (mp_int * a, int digits) /* first place a random non-zero digit */ do { - d = ((mp_digit) abs (MP_GEN_RANDOM())) & MP_MASK; + d = ((mp_digit) abs (int(MP_GEN_RANDOM()))) & MP_MASK; } while (d == 0); if ((res = mp_add_d (a, d, a)) != MP_OKAY) { @@ -6720,7 +6720,7 @@ mp_rand (mp_int * a, int digits) return res; } - if ((res = mp_add_d (a, ((mp_digit) abs (MP_GEN_RANDOM())), a)) != MP_OKAY) { + if ((res = mp_add_d (a, ((mp_digit) abs (int(MP_GEN_RANDOM()))), a)) != MP_OKAY) { return res; } } From fe754453f4903aa62dadff6b34f1b5855b321386 Mon Sep 17 00:00:00 2001 From: Alden Torres Date: Thu, 20 Oct 2016 00:14:03 -0400 Subject: [PATCH 8/9] backport of fix for LFS support in android (#1232) --- src/file.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/file.cpp b/src/file.cpp index 2d3fe2b89..2ad6ec50a 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -129,6 +129,9 @@ POSSIBILITY OF SUCH DAMAGE. #ifdef TORRENT_ANDROID #include #define lseek lseek64 +#define pread pread64 +#define pwrite pwrite64 +#define ftruncate ftruncate64 #endif #elif defined __APPLE__ && defined __MACH__ && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 From 5012fcf10b0c3a022ee10e5fc703943ce5888537 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 20 Oct 2016 00:15:26 -0400 Subject: [PATCH 9/9] fix bug in last-seen-complete (#1234) --- ChangeLog | 1 + src/bt_peer_connection.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 68b68e061..75c2b5cfc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix bug in last-seen-complete * remove file size limit in torrent_info filename constructor * fix tail-padding for last file in create_torrent * don't send user-agent in metadata http downloads or UPnP requests when diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index cd55acb8d..d99f9905c 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1861,7 +1861,7 @@ namespace libtorrent // there should be a version too // but where do we put that info? - int last_seen_complete = boost::uint8_t(root.dict_find_int_value("complete_ago", -1)); + int const last_seen_complete = root.dict_find_int_value("complete_ago", -1); if (last_seen_complete >= 0) set_last_seen_complete(last_seen_complete); std::string client_info = root.dict_find_string_value("v");