From dfabce38545026701971f2e192dc9704368b5a7b Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 5 Oct 2017 02:47:40 +0200 Subject: [PATCH 1/6] update build_dist.sh --- build_dist.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_dist.sh b/build_dist.sh index 3a7f67ddc..8269755c4 100755 --- a/build_dist.sh +++ b/build_dist.sh @@ -23,9 +23,9 @@ rm -f bindings/python/Makefile bindings/python/Makefile.in chmod a-x docs/*.rst docs/*.htm* src/*.cpp include/libtorrent/*.hpp ./autotool.sh -./configure --enable-python-binding --enable-examples=yes --enable-encryption --enable-tests=yes --with-boost-system=mt --with-boost-chrono=mt --with-boost-random=mt --with-boost-python=mt --with-openssl=/opt/local +./configure --enable-python-binding --enable-examples=yes --enable-encryption --enable-tests=yes --with-boost-system=mt --with-boost-chrono=mt --with-boost-random=mt --with-boost-python=mt --with-openssl=/usr/local/opt/openssl make V=1 -j8 check -./configure --enable-python-binding --enable-examples=yes --enable-encryption --with-boost-system=mt --with-boost-chrono=mt --with-boost-random=mt --with-boost-python=mt --with-openssl=/opt/local +./configure --enable-python-binding --enable-examples=yes --enable-encryption --with-boost-system=mt --with-boost-chrono=mt --with-boost-random=mt --with-boost-python=mt --with-openssl=/usr/local/opt/openssl make V=1 -j8 dist From ed31664ee3c022bec3de8be4155c3c610e748adf Mon Sep 17 00:00:00 2001 From: arvidn Date: Thu, 5 Oct 2017 12:09:24 +0200 Subject: [PATCH 2/6] deduce the second argument to iconv() instead of requiring it to be configured via a macro --- include/libtorrent/config.hpp | 12 ------------ src/escape_string.cpp | 20 +++++++++++++++----- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index 6cd412f38..cc9f09f61 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -194,13 +194,6 @@ POSSIBILITY OF SUCH DAMAGE. #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050 #define TORRENT_USE_EXECINFO 1 #endif - -#else // __APPLE__ -// FreeBSD has a reasonable iconv signature -// unless we're on glibc -#ifndef __GLIBC__ -# define TORRENT_ICONV_ARG(x) (x) -#endif #endif // __APPLE__ #define TORRENT_HAVE_MMAP 1 @@ -344,7 +337,6 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_IFCONF 1 #define TORRENT_USE_SYSCTL 1 #define TORRENT_USE_IPV6 0 -#define TORRENT_ICONV_ARG(x) (x) #define TORRENT_USE_WRITEV 0 #define TORRENT_USE_READV 0 @@ -456,10 +448,6 @@ int snprintf(char* buf, int len, char const* fmt, ...) #define TORRENT_OVERRIDE override #endif -#ifndef TORRENT_ICONV_ARG -#define TORRENT_ICONV_ARG(x) const_cast(x) -#endif - #if defined __GNUC__ || defined __clang__ #define TORRENT_FORMAT(fmt, ellipsis) __attribute__((__format__(__printf__, fmt, ellipsis))) #else diff --git a/src/escape_string.cpp b/src/escape_string.cpp index 2b892e059..cd1b972d3 100644 --- a/src/escape_string.cpp +++ b/src/escape_string.cpp @@ -515,6 +515,17 @@ namespace libtorrent #if TORRENT_USE_ICONV namespace { + + // this is a helper function to deduce the type of the second argument to + // the iconv() function. + + template + size_t call_iconv(size_t (&fun)(iconv_t, Input**, size_t*, char**, size_t*) + , iconv_t cd, char const** in, size_t* insize, char** out, size_t* outsize) + { + return fun(cd, const_cast(in), insize, out, outsize); + } + std::string iconv_convert_impl(std::string const& s, iconv_t h) { std::string ret; @@ -523,11 +534,10 @@ namespace { ret.resize(outsize); char const* in = s.c_str(); char* out = &ret[0]; - // posix has a weird iconv signature. implementations - // differ on what this signature should be, so we use - // a macro to let config.hpp determine it - size_t retval = iconv(h, TORRENT_ICONV_ARG(&in), &insize, - &out, &outsize); + // posix has a weird iconv() signature. implementations + // differ on the type of the second parameter. We use a helper template + // to deduce what we need to cast to. + size_t const retval = call_iconv(::iconv, h, &in, &insize, &out, &outsize); if (retval == size_t(-1)) return s; // if this string has an invalid utf-8 sequence in it, don't touch it if (insize != 0) return s; From 4e1c5738a25e2ae73b6b20d4c77201f586f1e6a5 Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 6 Oct 2017 11:08:50 +0200 Subject: [PATCH 3/6] back-port openssl API compat patch from master --- src/session_impl.cpp | 10 ++++++++-- src/torrent.cpp | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 9bc81567b..ab2ca1953 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -150,8 +150,13 @@ namespace #include #include -namespace -{ +// by openssl changelog at https://www.openssl.org/news/changelog.html +// Changes between 1.0.2h and 1.1.0 [25 Aug 2016] +// - Most global cleanup functions are no longer required because they are handled +// via auto-deinit. Affected function CRYPTO_cleanup_all_ex_data() +#if !defined(OPENSSL_API_COMPAT) || OPENSSL_API_COMPAT < 0x10100000L +namespace { + // openssl requires this to clean up internal // structures it allocates struct openssl_cleanup @@ -159,6 +164,7 @@ namespace ~openssl_cleanup() { CRYPTO_cleanup_all_ex_data(); } } openssl_global_destructor; } +#endif #endif // TORRENT_USE_OPENSSL diff --git a/src/torrent.cpp b/src/torrent.cpp index a89750050..3d09f9162 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1684,7 +1684,11 @@ namespace libtorrent using boost::asio::ssl::context; // this is needed for openssl < 1.0 to decrypt keys created by openssl 1.0+ +#if !defined(OPENSSL_API_COMPAT) || (OPENSSL_API_COMPAT < 0x10100000L) OpenSSL_add_all_algorithms(); +#else + OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS, nullptr); +#endif boost::uint64_t now = clock_type::now().time_since_epoch().count(); // assume 9 bits of entropy (i.e. about 1 millisecond) From cdd9f919997b8ad11f8db3ee7349576aa826bc53 Mon Sep 17 00:00:00 2001 From: arvidn Date: Fri, 6 Oct 2017 15:03:47 +0200 Subject: [PATCH 4/6] fix leak of torrent_peer objecs (entries in peer_list) --- ChangeLog | 1 + include/libtorrent/aux_/session_impl.hpp | 4 +- include/libtorrent/aux_/session_interface.hpp | 2 +- include/libtorrent/peer_list.hpp | 15 ++- src/peer_list.cpp | 25 +++-- src/torrent.cpp | 3 +- test/test_peer_list.cpp | 92 +++++++++---------- 7 files changed, 78 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 65b1f357e..89ca5a3c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 1.1.5 release + * fix leak of torrent_peer objecs (entries in peer_list) * fix leak of peer_class objects (when setting per-torrent rate limits) * expose peer_class API to python binding * fix integer overflow in whole_pieces_threshold logic diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index c923dbbb5..e912963bc 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -207,8 +207,8 @@ namespace libtorrent void open_listen_port(); - torrent_peer_allocator_interface* get_peer_allocator() TORRENT_OVERRIDE - { return &m_peer_allocator; } + torrent_peer_allocator_interface& get_peer_allocator() TORRENT_OVERRIDE + { return m_peer_allocator; } io_service& get_io_service() TORRENT_OVERRIDE { return m_io_service; } resolver_interface& get_resolver() TORRENT_OVERRIDE { return m_host_resolver; } diff --git a/include/libtorrent/aux_/session_interface.hpp b/include/libtorrent/aux_/session_interface.hpp index fcd2c4317..13099336e 100644 --- a/include/libtorrent/aux_/session_interface.hpp +++ b/include/libtorrent/aux_/session_interface.hpp @@ -152,7 +152,7 @@ namespace libtorrent { namespace aux virtual alert_manager& alerts() = 0; - virtual torrent_peer_allocator_interface* get_peer_allocator() = 0; + virtual torrent_peer_allocator_interface& get_peer_allocator() = 0; virtual io_service& get_io_service() = 0; virtual resolver_interface& get_resolver() = 0; diff --git a/include/libtorrent/peer_list.hpp b/include/libtorrent/peer_list.hpp index ae7d9d010..2892d1b4c 100644 --- a/include/libtorrent/peer_list.hpp +++ b/include/libtorrent/peer_list.hpp @@ -70,7 +70,6 @@ namespace libtorrent , loop_counter(0) , ip(NULL), port(0) , max_failcount(3) - , peer_allocator(NULL) {} bool is_paused; bool is_finished; @@ -97,9 +96,6 @@ namespace libtorrent // a connect candidate int max_failcount; - // this must be set to a torrent_peer allocator - torrent_peer_allocator_interface* peer_allocator; - // if any peer were removed during this call, they are returned in // this vector. The caller would want to make sure there are no // references to these torrent_peers anywhere @@ -110,7 +106,8 @@ namespace libtorrent { public: - peer_list(); + peer_list(torrent_peer_allocator_interface& alloc); + ~peer_list(); #if TORRENT_USE_I2P torrent_peer* add_i2p_peer(char const* destination, int src, char flags @@ -211,6 +208,10 @@ namespace libtorrent private: + // not copyable + peer_list(peer_list const&); + peer_list& operator=(peer_list const&); + void recalculate_connect_candidates(torrent_state* state); void update_connect_candidates(int delta); @@ -244,6 +245,10 @@ namespace libtorrent // if so, don't delete it. torrent_peer* m_locked_peer; + // the peer allocator, as stored from the constructor + // this must be available in the destructor to free all peers + torrent_peer_allocator_interface& m_peer_allocator; + // the number of seeds in the torrent_peer list boost::uint32_t m_num_seeds:31; diff --git a/src/peer_list.cpp b/src/peer_list.cpp index 12adb44a1..4c4167107 100644 --- a/src/peer_list.cpp +++ b/src/peer_list.cpp @@ -121,8 +121,9 @@ namespace namespace libtorrent { - peer_list::peer_list() + peer_list::peer_list(torrent_peer_allocator_interface& alloc) : m_locked_peer(NULL) + , m_peer_allocator(alloc) , m_num_seeds(0) , m_finished(0) , m_round_robin(0) @@ -132,6 +133,15 @@ namespace libtorrent thread_started(); } + peer_list::~peer_list() + { + for (peers_t::iterator i = m_peers.begin() + , end(m_peers.end()); i != end; ++i) + { + m_peer_allocator.free_peer_entry(*i); + } + } + void peer_list::set_max_failcount(torrent_state* state) { if (state->max_failcount == m_max_failcount) return; @@ -301,7 +311,7 @@ namespace libtorrent (*i)->in_use = false; #endif - state->peer_allocator->free_peer_entry(*i); + m_peer_allocator.free_peer_entry(*i); m_peers.erase(i); } @@ -745,7 +755,7 @@ namespace libtorrent #else bool is_v6 = false; #endif - torrent_peer* p = state->peer_allocator->allocate_peer_entry( + torrent_peer* p = m_peer_allocator.allocate_peer_entry( is_v6 ? torrent_peer_allocator_interface::ipv6_peer_type : torrent_peer_allocator_interface::ipv4_peer_type); if (p == 0) return false; @@ -1030,7 +1040,7 @@ namespace libtorrent { // we don't have any info about this peer. // add a new entry - p = state->peer_allocator->allocate_peer_entry(torrent_peer_allocator_interface::i2p_peer_type); + p = m_peer_allocator.allocate_peer_entry(torrent_peer_allocator_interface::i2p_peer_type); if (p == NULL) return NULL; new (p) i2p_peer(destination, true, src); @@ -1044,7 +1054,7 @@ namespace libtorrent p->in_use = false; #endif - state->peer_allocator->free_peer_entry(p); + m_peer_allocator.free_peer_entry(p); return 0; } } @@ -1106,7 +1116,7 @@ namespace libtorrent #else bool is_v6 = false; #endif - p = state->peer_allocator->allocate_peer_entry( + p = m_peer_allocator.allocate_peer_entry( is_v6 ? torrent_peer_allocator_interface::ipv6_peer_type : torrent_peer_allocator_interface::ipv4_peer_type); if (p == NULL) return NULL; @@ -1127,7 +1137,8 @@ namespace libtorrent #if TORRENT_USE_ASSERTS p->in_use = false; #endif - state->peer_allocator->free_peer_entry(p); + // TODO: 3 this is not exception safe! + m_peer_allocator.free_peer_entry(p); return 0; } state->first_time_seen = true; diff --git a/src/torrent.cpp b/src/torrent.cpp index 3d09f9162..63f8bec49 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1172,7 +1172,7 @@ namespace libtorrent void torrent::need_peer_list() { if (m_peer_list) return; - m_peer_list.reset(new peer_list); + m_peer_list.reset(new peer_list(m_ses.get_peer_allocator())); } void torrent::handle_disk_error(disk_io_job const* j, peer_connection* c) @@ -11503,7 +11503,6 @@ namespace { : settings().get_int(settings_pack::max_peerlist_size); ret.min_reconnect_time = settings().get_int(settings_pack::min_reconnect_time); - ret.peer_allocator = m_ses.get_peer_allocator(); ret.ip = &m_ses.external_address(); ret.port = m_ses.listen_port(); ret.max_failcount = settings().get_int(settings_pack::max_failcount); diff --git a/test/test_peer_list.cpp b/test/test_peer_list.cpp index 5a051c4d4..ba3a36aeb 100644 --- a/test/test_peer_list.cpp +++ b/test/test_peer_list.cpp @@ -162,15 +162,13 @@ bool has_peer(peer_list const& p, tcp::endpoint const& ep) return its.first != its.second; } -torrent_state init_state(torrent_peer_allocator& allocator - , external_ip& ext_ip) +torrent_state init_state(external_ip& ext_ip) { torrent_state st; st.is_finished = false; st.is_paused = false; st.max_peerlist_size = 1000; st.allow_multiple_connections_per_ip = false; - st.peer_allocator = &allocator; st.ip = &ext_ip; st.port = 9999; return st; @@ -206,9 +204,9 @@ static external_ip ext_ip; // when disallowing it TORRENT_TEST(multiple_ips_disallowed) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; TEST_EQUAL(p.num_connect_candidates(), 0); torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), 0, 0, &st); @@ -228,10 +226,10 @@ TORRENT_TEST(multiple_ips_disallowed) // when allowing it TORRENT_TEST(multiple_ips_allowed) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = true; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), 0, 0, &st); TEST_EQUAL(p.num_connect_candidates(), 1); @@ -250,10 +248,10 @@ TORRENT_TEST(multiple_ips_allowed) // with allow_multiple_connections_per_ip enabled TORRENT_TEST(multiple_ips_allowed2) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = true; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), 0, 0, &st); TEST_EQUAL(p.num_connect_candidates(), 1); @@ -289,10 +287,10 @@ TORRENT_TEST(multiple_ips_allowed2) // with allow_multiple_connections_per_ip disabled TORRENT_TEST(multiple_ips_disallowed2) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = p.add_peer(ep("10.0.0.2", 3000), 0, 0, &st); TEST_EQUAL(p.num_connect_candidates(), 1); @@ -323,10 +321,10 @@ TORRENT_TEST(multiple_ips_disallowed2) // and update_peer_port TORRENT_TEST(update_peer_port) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; TEST_EQUAL(p.num_connect_candidates(), 0); boost::shared_ptr c @@ -347,10 +345,10 @@ TORRENT_TEST(update_peer_port) // and update_peer_port, causing collission TORRENT_TEST(update_peer_port_collide) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = true; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer2 = p.add_peer(ep("10.0.0.1", 4000), 0, 0, &st); @@ -378,10 +376,10 @@ TORRENT_TEST(update_peer_port_collide) // test ip filter TORRENT_TEST(ip_filter) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // add peer 1 @@ -418,10 +416,10 @@ TORRENT_TEST(ip_filter) // test port filter TORRENT_TEST(port_filter) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // add peer 1 @@ -458,10 +456,10 @@ TORRENT_TEST(port_filter) // test banning peers TORRENT_TEST(ban_peers) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 4000)); @@ -499,11 +497,11 @@ TORRENT_TEST(ban_peers) // test erase_peers when we fill up the peer list TORRENT_TEST(erase_peers) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.max_peerlist_size = 100; st.allow_multiple_connections_per_ip = true; - peer_list p; + peer_list p(allocator); t.m_p = &p; for (int i = 0; i < 100; ++i) @@ -532,11 +530,11 @@ TORRENT_TEST(erase_peers) // test set_ip_filter TORRENT_TEST(set_ip_filter) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); std::vector
banned; mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; for (int i = 0; i < 100; ++i) @@ -563,11 +561,11 @@ TORRENT_TEST(set_ip_filter) // test set_port_filter TORRENT_TEST(set_port_filter) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); std::vector
banned; mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; for (int i = 0; i < 100; ++i) @@ -594,10 +592,10 @@ TORRENT_TEST(set_port_filter) // test set_max_failcount TORRENT_TEST(set_max_failcount) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; for (int i = 0; i < 100; ++i) @@ -624,10 +622,10 @@ TORRENT_TEST(set_max_failcount) // test set_seed TORRENT_TEST(set_seed) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; for (int i = 0; i < 100; ++i) @@ -658,11 +656,11 @@ TORRENT_TEST(set_seed) // test has_peer TORRENT_TEST(has_peer) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); std::vector
banned; mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = add_peer(p, st, ep("10.10.0.1", 10)); @@ -691,11 +689,11 @@ TORRENT_TEST(has_peer) // test connect_candidates torrent_finish TORRENT_TEST(connect_candidates_finish) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); std::vector
banned; mock_torrent t(&st); - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = add_peer(p, st, ep("10.10.0.1", 10)); @@ -730,10 +728,10 @@ TORRENT_TEST(connect_candidates_finish) // test self-connection TORRENT_TEST(self_connection) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // add and connect peer @@ -762,10 +760,10 @@ TORRENT_TEST(self_connection) // test double connection (both incoming) TORRENT_TEST(double_connection) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // we are 10.0.0.1 and the other peer is 10.0.0.2 @@ -792,10 +790,10 @@ TORRENT_TEST(double_connection) // test double connection (we loose) TORRENT_TEST(double_connection_loose) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // we are 10.0.0.1 and the other peer is 10.0.0.2 @@ -823,10 +821,10 @@ TORRENT_TEST(double_connection_loose) // test double connection (we win) TORRENT_TEST(double_connection_win) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; // we are 10.0.0.1 and the other peer is 10.0.0.2 @@ -854,11 +852,11 @@ TORRENT_TEST(double_connection_win) // test incoming connection when we are at the list size limit TORRENT_TEST(incoming_size_limit) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); st.max_peerlist_size = 5; mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 8080)); @@ -900,11 +898,11 @@ TORRENT_TEST(incoming_size_limit) // test new peer when we are at the list size limit TORRENT_TEST(new_peer_size_limit) { - torrent_state st = init_state(allocator, ext_ip); + torrent_state st = init_state(ext_ip); st.max_peerlist_size = 5; mock_torrent t(&st); st.allow_multiple_connections_per_ip = false; - peer_list p; + peer_list p(allocator); t.m_p = &p; torrent_peer* peer1 = add_peer(p, st, ep("10.0.0.1", 8080)); From 8ba5845643908d81ba89148d972994fab79db714 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 7 Oct 2017 15:26:46 +0200 Subject: [PATCH 5/6] don't hard-code the paths to find openssl on mac (but default to picking up brew). Add two new jam features, openssl-lib and openssl-include that can be used to specify which openssl to link against --- Jamfile | 127 ++++++++++++++++++++++++++++++++++++---------- appveyor.yml | 47 ++++++++--------- docs/building.rst | 17 +++++++ 3 files changed, 137 insertions(+), 54 deletions(-) diff --git a/Jamfile b/Jamfile index 2f42a98d1..ce50c438d 100644 --- a/Jamfile +++ b/Jamfile @@ -61,34 +61,30 @@ VERSION = 1.1.5 ; # rule for linking the correct libraries depending # on features and target-os -rule linking ( properties * ) +rule link-openssl ( properties * ) { local result ; # openssl libraries, if enabled # exclude gcc from a regular windows build to make mingw # link against the regular unix library name - if openssl in $(properties) + if pre1.1 in $(properties) + && windows in $(properties) + && ! gcc in $(properties) { - if pre1.1 in $(properties) - && windows in $(properties) - && ! gcc in $(properties) - { - result += ssleay32 - libeay32 - ; - } - else - { - # on windows the library names were changed to be in line with other - # system starting with OpenSSL 1.1 - result += crypto ssl ; - } + result += ssleay32 + libeay32 + ; + } + else + { + # on windows the library names were changed to be in line with other + # system starting with OpenSSL 1.1 + result += crypto ssl ; } # windows needs some more libraries when using openSSL - if openssl in $(properties) - && windows in $(properties) + if windows in $(properties) && ! gcc in $(properties) { result += advapi32 @@ -97,7 +93,13 @@ rule linking ( properties * ) gdi32 ; } + echo "link openssl = " $(result) ; + return $(result) ; +} +rule linking ( properties * ) +{ + local result ; if on in $(properties) { result += /libsimulator//simulator ; @@ -369,7 +371,7 @@ rule building ( properties * ) return $(result) ; } -rule tag ( name : type ? : property-set ) +rule tag ( name : type ? : property-set ) { name = [ virtual-target.add-prefix-and-suffix $(name) : $(type) : $(property-set) ] ; @@ -382,6 +384,78 @@ rule tag ( name : type ? : property-set ) return $(name) ; } +# the search path to pick up the openssl libraries from. This is the +# property of those libraries +rule openssl-lib-path ( properties * ) +{ + local OPENSSL_LIB = [ feature.get-values : $(properties) ] ; + + if darwin in $(properties) && $(OPENSSL_LIB) = "" + { + # on macOS, default to pick up openssl from the homebrew installation + # brew install openssl + OPENSSL_LIB = /usr/local/opt/openssl/lib ; + } + else if windows in $(properties) + && gcc in $(properties) + && $(OPENSSL_LIB) = "" + { + # on mingw, assume openssl is installed in c:\OpenSSL-Win32 by default + OPENSSL_LIB = c:\\OpenSSL-Win32\\lib ; + } + else if windows in $(properties) && $(OPENSSL_LIB) = "" + { + # on windows, just assume openssl is installed to c:\openssl + if 64 in $(properties) + { OPENSSL_LIB = c:\\openssl\\lib64 ; } + else + { OPENSSL_LIB = c:\\openssl\\lib ; } + } + + local result ; + result += $(OPENSSL_LIB) ; + echo "openssl-lib-path = " $(result) ; + return $(result) ; +} + +# the include path to pick up openssl headers from. This is the +# usage-requirement for the openssl-related libraries +rule openssl-include-path ( properties * ) +{ + local OPENSSL_INCLUDE = [ feature.get-values : $(properties) ] ; + + if darwin in $(properties) && $(OPENSSL_INCLUDE) = "" + { + # on macOS, default to pick up openssl from the homebrew installation + # brew install openssl + OPENSSL_INCLUDE = /usr/local/opt/openssl/include ; + } + else if windows in $(properties) + && gcc in $(properties) + && $(OPENSSL_INCLUDE) = "" + { + # on mingw, assume openssl is installed in c:\OpenSSL-Win32 by default + OPENSSL_INCLUDE = c:\\OpenSSL-Win32\\include ; + } + else if windows in $(properties) && $(OPENSSL_INCLUDE) = "" + { + # on windows, just assume openssl is installed to c:\openssl + # not sure if there's a better way to find out where it may be + if 64 in $(properties) + { OPENSSL_INCLUDE = c:\\openssl\\include64 ; } + else + { OPENSSL_INCLUDE = c:\\openssl\\include ; } + } + + local result ; + result += $(OPENSSL_INCLUDE) ; + echo "openssl-include-path = " $(result) ; + return $(result) ; +} + +feature openssl-lib : : free path ; +feature openssl-include : : free path ; + feature ipv6 : on off : composite propagated link-incompatible ; feature.compose off : TORRENT_USE_IPV6=0 ; @@ -527,9 +601,12 @@ variant test_barebones : debug on on multi on ; +lib crypto : : crypto z @openssl-lib-path : : @openssl-include-path ; +lib ssl : : ssl crypto @openssl-lib-path : : @openssl-include-path ; + # required for openssl on windows -lib ssleay32 : : ssleay32 ; -lib libeay32 : : libeay32 ; +lib ssleay32 : : ssleay32 @openssl-lib-path : : @openssl-include-path ; +lib libeay32 : : libeay32 @openssl-lib-path : : @openssl-include-path ; lib advapi32 : : advapi32 ; lib user32 : : user32 ; lib shell32 : : shell32 ; @@ -548,12 +625,7 @@ lib gcrypt : : gcrypt shared /opt/local/lib ; lib z : : shared z ; lib dl : : shared dl ; -# pick up openssl on macos from brew -lib crypto : : crypto z darwin /usr/local/opt/openssl/lib : shared : /usr/local/opt/openssl/include ; -lib ssl : : ssl crypto darwin /usr/local/opt/openssl/lib : shared : /usr/local/opt/openssl/include ; - -lib crypto : : crypto z : shared ; -lib ssl : : ssl crypto : shared ; +alias openssl-libraries : : : : @link-openssl ; # time functions used on linux require librt lib librt : : rt shared ; @@ -758,6 +830,7 @@ lib torrent shared:TORRENT_BUILDING_SHARED BOOST_NO_DEPRECATED shared:BOOST_SYSTEM_SOURCE + openssl:openssl-libraries on:src/kademlia/$(KADEMLIA_SOURCES).cpp on:ed25519/src/$(ED25519_SOURCES).cpp diff --git a/appveyor.yml b/appveyor.yml index 808ce94ab..05493f63a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,30 +10,20 @@ environment: compiler: msvc-14.0 os: Visual Studio 2015 sim: 1 - linkflags: '"/LIBPATH:C:\\openssl-1.0.1p-vs2015\\lib"' - include: '"c:\\openssl-1.0.1p-vs2015\\include"' - variant: test_debug compiler: msvc-12.0 os: Visual Studio 2013 x64: 1 - linkflags: '"/LIBPATH:C:\\openssl-1.0.1p-vs2013\\lib64"' - include: '"c:\\openssl-1.0.1p-vs2013\\include"' - variant: test_debug python_package: 1 compiler: msvc-10.0 os: Visual Studio 2015 - linkflags: '"/LIBPATH:C:\\openssl-1.0.1p-vs2010\\lib"' - include: '"c:\\openssl-1.0.1p-vs2010\\include"' - variant: test_barebones compiler: msvc-12.0 os: Visual Studio 2013 - linkflags: '"/LIBPATH:C:\\openssl-1.0.1p-vs2013\\lib"' - include: '"c:\\openssl-1.0.1p-vs2013\\include"' - variant: test_release compiler: msvc-12.0 os: Visual Studio 2013 - linkflags: '"/LIBPATH:C:\\openssl-1.0.1p-vs2013\\lib"' - include: '"c:\\openssl-1.0.1p-vs2013\\include"' # mingw and boost.random don't like each other. Comment this back in once there # is support @@ -55,10 +45,11 @@ install: - if %compiler% == msvc-12.0 ( echo extracting openssl-2013 & 7z x -oc:\ -aoa openssl-1.0.1p-vs2013.7z > nul - & copy c:\openssl-1.0.1p-vs2013\lib64\ssleay32MT.lib c:\openssl-1.0.1p-vs2013\lib64\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2013\lib64\libeay32MT.lib c:\openssl-1.0.1p-vs2013\lib64\libeay32.lib - & copy c:\openssl-1.0.1p-vs2013\lib\ssleay32MT.lib c:\openssl-1.0.1p-vs2013\lib\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2013\lib\libeay32MT.lib c:\openssl-1.0.1p-vs2013\lib\libeay32.lib + & rename c:\openssl-1.0.1p-vs2013 openssl + & copy c:\openssl\lib64\ssleay32MT.lib c:\openssl\lib64\ssleay32.lib + & copy c:\openssl\lib64\libeay32MT.lib c:\openssl\lib64\libeay32.lib + & copy c:\openssl\lib\ssleay32MT.lib c:\openssl\lib\ssleay32.lib + & copy c:\openssl\lib\libeay32MT.lib c:\openssl\lib\libeay32.lib ) - if %compiler% == msvc-10.0 ( if not exist openssl-1.0.1p-vs2010.7z ( @@ -69,10 +60,11 @@ install: - if %compiler% == msvc-10.0 ( echo extracting openssl-2010 & 7z x -oc:\ -aoa openssl-1.0.1p-vs2010.7z > nul - & copy c:\openssl-1.0.1p-vs2010\lib64\ssleay32MT.lib c:\openssl-1.0.1p-vs2010\lib64\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2010\lib64\libeay32MT.lib c:\openssl-1.0.1p-vs2010\lib64\libeay32.lib - & copy c:\openssl-1.0.1p-vs2010\lib\ssleay32MT.lib c:\openssl-1.0.1p-vs2010\lib\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2010\lib\libeay32MT.lib c:\openssl-1.0.1p-vs2010\lib\libeay32.lib + & rename c:\openssl-1.0.1p-vs2010 openssl + & copy c:\openssl\lib64\ssleay32MT.lib c:\openssl\lib64\ssleay32.lib + & copy c:\openssl\lib64\libeay32MT.lib c:\openssl\lib64\libeay32.lib + & copy c:\openssl\lib\ssleay32MT.lib c:\openssl\lib\ssleay32.lib + & copy c:\openssl\lib\libeay32MT.lib c:\openssl\lib\libeay32.lib ) - if %compiler% == msvc-14.0 ( if not exist openssl-1.0.1p-vs2015.7z ( @@ -83,10 +75,11 @@ install: - if %compiler% == msvc-14.0 ( echo extracting openssl-2015 & 7z x -oc:\ -aoa openssl-1.0.1p-vs2015.7z > nul - & copy c:\openssl-1.0.1p-vs2015\lib64\ssleay32MT.lib c:\openssl-1.0.1p-vs2015\lib64\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2015\lib64\libeay32MT.lib c:\openssl-1.0.1p-vs2015\lib64\libeay32.lib - & copy c:\openssl-1.0.1p-vs2015\lib\ssleay32MT.lib c:\openssl-1.0.1p-vs2015\lib\ssleay32.lib - & copy c:\openssl-1.0.1p-vs2015\lib\libeay32MT.lib c:\openssl-1.0.1p-vs2015\lib\libeay32.lib + & rename c:\openssl-1.0.1p-vs2015 openssl + & copy c:\openssl\lib64\ssleay32MT.lib c:\openssl\lib64\ssleay32.lib + & copy c:\openssl\lib64\libeay32MT.lib c:\openssl\lib64\libeay32.lib + & copy c:\openssl\lib\ssleay32MT.lib c:\openssl\lib\ssleay32.lib + & copy c:\openssl\lib\libeay32MT.lib c:\openssl\lib\libeay32.lib ) - cd %ROOT_DIRECTORY% - set BOOST_ROOT=c:\Libraries\boost_1_63_0 @@ -117,12 +110,12 @@ build_script: - if not defined x64 ( cd %ROOT_DIRECTORY%\examples & if %compiler% == msvc-14.0 ( - b2.exe --hash -j2 openssl-version=pre1.1 address-model=32 %compiler% variant=%variant% debug-iterators=on picker-debugging=on invariant-checks=full linkflags=%linkflags% include=%include% link=shared bt-get bt-get2 + b2.exe --hash -j2 crypto=openssl openssl-version=pre1.1 address-model=32 %compiler% variant=%variant% debug-iterators=on picker-debugging=on invariant-checks=full link=shared bt-get bt-get2 ) else ( - b2.exe --hash -j2 openssl-version=pre1.1 address-model=32 %compiler% variant=%variant% debug-iterators=on picker-debugging=on invariant-checks=full linkflags=%linkflags% include=%include% link=shared + b2.exe --hash -j2 crypto=openssl openssl-version=pre1.1 address-model=32 %compiler% variant=%variant% debug-iterators=on picker-debugging=on invariant-checks=full link=shared ) & cd %ROOT_DIRECTORY%\bindings\python - & b2.exe --hash -j2 openssl-version=pre1.1 %compiler% stage_module install-dependencies=on variant=%variant% libtorrent-link=shared linkflags=%linkflags% include=%include% + & b2.exe --hash -j2 openssl-version=pre1.1 %compiler% stage_module install-dependencies=on variant=%variant% libtorrent-link=shared crypto=openssl & python test.py & if defined python_package ( python setup.py --bjam bdist_msi ) ) @@ -130,9 +123,9 @@ build_script: test_script: - cd %ROOT_DIRECTORY%\test - if defined x64 ( - appveyor-retry b2.exe --hash -j2 openssl-version=pre1.1 address-model=64 win-tests %compiler% variant=%variant% link=shared linkflags=%linkflags% include=%include% + appveyor-retry b2.exe --hash -j2 openssl-version=pre1.1 address-model=64 win-tests %compiler% variant=%variant% link=shared ) else ( - appveyor-retry b2.exe --hash -j2 openssl-version=pre1.1 address-model=32 win-tests %compiler% variant=%variant% link=shared linkflags=%linkflags% include=%include% + appveyor-retry b2.exe --hash -j2 openssl-version=pre1.1 address-model=32 win-tests %compiler% variant=%variant% link=shared ) - if defined sim ( cd %ROOT_DIRECTORY%\simulation diff --git a/docs/building.rst b/docs/building.rst index 0fd59886a..686be6fcd 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -237,6 +237,14 @@ windows format (``c:/boost_1_64_0``). The ``Jamfile`` will define ``NDEBUG`` when it's building a release build. For more build configuration flags see `Build configurations`_. +When enabling linking against openssl (by setting the ``crypto`` feature to +``openssl``) the Jamfile will look in some default directory for the openssl +headers and libraries. On macOS, it will look for the homebrew openssl package. +On windows it will look in ``c:\openssl`` and mingw in ``c:\OpenSSL-Win32``. + +To customize the library path and include path for openssl, set the features +``openssl-lib`` and ``openssl-include`` respectively. + Build features: +--------------------------+----------------------------------------------------+ @@ -247,6 +255,13 @@ Build features: | | * ``shared`` - links dynamically against the boost | | | libraries. | +--------------------------+----------------------------------------------------+ +| ``openssl-lib`` | can be used to specify the directory where libssl | +| | and libcrypto are installed (or the windows | +| | counterparts). | ++--------------------------+----------------------------------------------------+ +| ``openssl-include`` | can be used to specify the include directory where | +| | the openssl headers are installed. | ++--------------------------+----------------------------------------------------+ | ``logging`` | * ``off`` - logging alerts disabled. The | | | reason to disable logging is to keep the binary | | | size low where that matters. | @@ -282,6 +297,8 @@ Build features: | | implementation. | | | * ``openssl`` - links against openssl and | | | libcrypto to use for SHA-1 hashing. | +| | This also enables HTTPS-tracker support and | +| | support for bittorrent over SSL. | | | * ``gcrypt`` - links against libgcrypt to use for | | | SHA-1 hashing. | +--------------------------+----------------------------------------------------+ From f0801490817a53a456f6501f2c6a1a2783223b61 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sun, 8 Oct 2017 02:04:56 +0200 Subject: [PATCH 6/6] fix parsing of torrents with certain invalid filenames --- ChangeLog | 1 + src/torrent_info.cpp | 9 +++++++++ test/Makefile.am | 2 ++ test/test_torrent_info.cpp | 10 ++++++++++ test/test_torrents/invalid_filename.torrent | 1 + test/test_torrents/invalid_filename2.torrent | 1 + 6 files changed, 24 insertions(+) create mode 100644 test/test_torrents/invalid_filename.torrent create mode 100644 test/test_torrents/invalid_filename2.torrent diff --git a/ChangeLog b/ChangeLog index 89ca5a3c4..74f5398a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 1.1.5 release + * fix parsing of torrents with certain invalid filenames * fix leak of torrent_peer objecs (entries in peer_list) * fix leak of peer_class objects (when setting per-torrent rate limits) * expose peer_class API to python binding diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index aa17bc258..b83043725 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -431,6 +431,7 @@ namespace libtorrent if (p && p.list_size() > 0) { + std::size_t const orig_path_len = path.size(); int const preallocate = path.size() + path_length(p, ec); if (ec) return false; path.reserve(preallocate); @@ -450,6 +451,14 @@ namespace libtorrent } sanitize_append_path_element(path, e.string_ptr(), e.string_length()); } + + // if all path elements were sanitized away, we need to use another + // name instead + if (path.size() == orig_path_len) + { + path += TORRENT_SEPARATOR; + path += "_"; + } } else if (file_flags & file_storage::flag_pad_file) { diff --git a/test/Makefile.am b/test/Makefile.am index f41a95901..7aab670e1 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -109,6 +109,8 @@ EXTRA_DIST = Jamfile \ test_torrents/url_seed_multi_space.torrent \ test_torrents/url_seed_multi_space_nolist.torrent \ test_torrents/whitespace_url.torrent \ + test_torrents/invalid_filename.torrent \ + test_torrents/invalid_filename2.torrent \ mutable_test_torrents/test1.torrent \ mutable_test_torrents/test1_pad_files.torrent \ mutable_test_torrents/test1_single.torrent\ diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 2311750b2..8d3b4966b 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -134,6 +134,8 @@ static test_torrent_t test_torrents[] = { "unordered.torrent" }, { "symlink_zero_size.torrent" }, { "pad_file_no_path.torrent" }, + { "invalid_filename.torrent" }, + { "invalid_filename2.torrent" }, }; struct test_failing_torrent_t @@ -769,6 +771,14 @@ TORRENT_TEST(parse_torrents) TEST_EQUAL(ti->num_files(), 2); TEST_EQUAL(ti->files().file_path(1), combine_path(".pad", "0")); } + else if (std::string(test_torrents[i].file) == "invalid_filename.torrent") + { + TEST_EQUAL(ti->num_files(), 2); + } + else if (std::string(test_torrents[i].file) == "invalid_filename2.torrent") + { + TEST_EQUAL(ti->num_files(), 3); + } file_storage const& fs = ti->files(); for (int i = 0; i < fs.num_files(); ++i) diff --git a/test/test_torrents/invalid_filename.torrent b/test/test_torrents/invalid_filename.torrent new file mode 100644 index 000000000..6e2bfc5ea --- /dev/null +++ b/test/test_torrents/invalid_filename.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1419490173e4:infod5:filesld6:lengthi51200e4:pathl1:feed6:lengthi14336e4:pathl1:.eee4:name5:\est212:piece lengthi16384e6:pieces80:01234567890123456789012345678901234567890123456789012345678901234567890123456789ee diff --git a/test/test_torrents/invalid_filename2.torrent b/test/test_torrents/invalid_filename2.torrent new file mode 100644 index 000000000..b63e17484 --- /dev/null +++ b/test/test_torrents/invalid_filename2.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1419490173e4:infod5:filesld6:lengthi51200e4:pathl1:feed6:lengthi14335e4:pathl1:.1:.eed6:lengthi1e4:pathl1:/1:.eee4:name5:\est212:piece lengthi16384e6:pieces80:01234567890123456789012345678901234567890123456789012345678901234567890123456789ee