diff --git a/ChangeLog b/ChangeLog index dc9fa25d1..3df36021b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -32,6 +32,9 @@ 1.1.1 release + * update puff.c for gzip inflation + * add dht_bootstrap_node a setting in settings_pack (and add default) + * make pad-file and symlink support conform to BEP47 * fix piece picker bug that could result in division by zero * fix value of current_tracker when all tracker failed * deprecate lt_trackers extension diff --git a/bindings/python/test.py b/bindings/python/test.py index 593a7678d..de9a2b898 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -26,7 +26,7 @@ class test_create_torrent(unittest.TestCase): class test_torrent_handle(unittest.TestCase): def test_torrent_handle(self): - ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + 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()}) @@ -92,7 +92,7 @@ class test_torrent_info(unittest.TestCase): # the file_strage object is only iterable for backwards compatibility if not hasattr(lt, 'version'): return - ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories, 'enable_dht': False}) ti = lt.torrent_info('url_seed_multi.torrent'); files = ti.files() @@ -109,7 +109,7 @@ class test_alerts(unittest.TestCase): def test_alert(self): - ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories, 'enable_dht': False}) ti = lt.torrent_info('base.torrent'); h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) st = h.status() @@ -134,7 +134,7 @@ class test_alerts(unittest.TestCase): self.assertEqual(st.save_path, os.getcwd()) def test_pop_alerts(self): - ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories, 'enable_dht': False}) ses.async_add_torrent({"ti": lt.torrent_info("base.torrent"), "save_path": "."}) # this will cause an error (because of duplicate torrents) and the @@ -176,7 +176,7 @@ class test_sha1hash(unittest.TestCase): class test_session(unittest.TestCase): def test_post_session_stats(self): - s = lt.session({'alert_mask': lt.alert.category_t.stats_notification}) + s = lt.session({'alert_mask': lt.alert.category_t.stats_notification, 'enable_dht': False}) s.post_session_stats() a = s.wait_for_alert(1000) self.assertTrue(isinstance(a, lt.session_stats_alert)) @@ -187,7 +187,7 @@ class test_session(unittest.TestCase): # this detects whether libtorrent was built with deprecated APIs if hasattr(lt, 'version'): - s = lt.session({}) + s = lt.session({'enable_dht': False}) sett = lt.session_settings() sett.num_want = 10; s.set_settings(sett) @@ -196,7 +196,7 @@ class test_session(unittest.TestCase): def test_apply_settings(self): - s = lt.session({}) + s = lt.session({'enable_dht': False}) s.apply_settings({'num_want': 66, 'user_agent': 'test123'}) self.assertEqual(s.get_settings()['num_want'], 66) self.assertEqual(s.get_settings()['user_agent'], 'test123') diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 42a3f9c74..0c119d58d 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -696,6 +696,7 @@ namespace libtorrent void update_dht(); void update_count_slow(); void update_peer_fingerprint(); + void update_dht_bootstrap_nodes(); void update_socket_buffer_size(); void update_dht_announce_interval(); diff --git a/include/libtorrent/bdecode.hpp b/include/libtorrent/bdecode.hpp index 876689b31..7063f0c87 100644 --- a/include/libtorrent/bdecode.hpp +++ b/include/libtorrent/bdecode.hpp @@ -110,7 +110,7 @@ namespace bdecode_errors { // Not an error no_error = 0, - // expected string in bencoded string + // expected digit in bencoded string expected_digit, // expected colon in bencoded string expected_colon, diff --git a/include/libtorrent/puff.hpp b/include/libtorrent/puff.hpp index a850e59dd..5bd50b577 100644 --- a/include/libtorrent/puff.hpp +++ b/include/libtorrent/puff.hpp @@ -25,9 +25,7 @@ /* * See puff.c for purpose and usage. */ -#include - int puff(unsigned char *dest, /* pointer to destination pointer */ - std::uint32_t *destlen, /* amount of output space */ - const unsigned char *source, /* pointer to source data pointer */ - std::uint32_t *sourcelen); /* amount of input available */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 15432e0ed..b97d4addf 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -328,7 +328,7 @@ namespace libtorrent // session_proxy(); // ~session_proxy() // }; - session_proxy abort() { return session_proxy(m_io_service, m_thread, m_impl); } + session_proxy abort(); private: diff --git a/include/libtorrent/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index c42b62959..3bb230b22 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -213,6 +213,15 @@ namespace libtorrent // used as the peer-id peer_fingerprint, + // This is a comma-separated list of IP port-pairs. They will be added + // to the DHT node (if it's enabled) as back-up nodes in case we don't + // know of any. This setting will contain one or more bootstrap nodes + // by default. + // + // Changing these after the DHT has been started may not have any + // effect until the DHT is restarted. + dht_bootstrap_nodes, + max_string_setting_internal }; diff --git a/include/libtorrent/string_util.hpp b/include/libtorrent/string_util.hpp index eb045bcda..71e80aa7b 100644 --- a/include/libtorrent/string_util.hpp +++ b/include/libtorrent/string_util.hpp @@ -79,6 +79,12 @@ namespace libtorrent TORRENT_EXTRA_EXPORT std::string print_listen_interfaces( std::vector const& in); + // this parses the string that's used as the liste_interfaces setting. + // it is a comma-separated list of IP or device names with ports. For + // example: "eth0:6881,eth1:6881" or "127.0.0.1:6881" + TORRENT_EXTRA_EXPORT void parse_comma_separated_string_port( + std::string const& in, std::vector >& out); + // this parses the string that's used as the outgoing_interfaces setting. // it is a comma separated list of IPs and device names. For example: // "eth0, eth1, 127.0.0.1" diff --git a/simulation/Jamfile b/simulation/Jamfile index f95b9bea2..0bae63d04 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -40,6 +40,7 @@ alias libtorrent-sims : [ run test_super_seeding.cpp ] [ run test_utp.cpp ] [ run test_dht.cpp ] + [ run test_dht_bootstrap.cpp ] [ run test_dht_storage.cpp ] [ run test_pe_crypto.cpp ] [ run test_metadata_extension.cpp ] diff --git a/simulation/fake_peer.hpp b/simulation/fake_peer.hpp index 833417573..319b48ae8 100644 --- a/simulation/fake_peer.hpp +++ b/simulation/fake_peer.hpp @@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/sha1_hash.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/io.hpp" +#include "libtorrent/bdecode.hpp" using namespace sim; @@ -282,6 +283,56 @@ inline void add_fake_peers(lt::torrent_handle& h, int const n = 5) } } +struct fake_node +{ + fake_node(simulation& sim, char const* ip, int port = 6881) + : m_ios(sim, asio::ip::address::from_string(ip)) + , m_socket(m_ios) + , m_tripped(false) + { + boost::system::error_code ec; + m_socket.open(asio::ip::udp::v4(), ec); + TEST_CHECK(!ec); + m_socket.bind(asio::ip::udp::endpoint(asio::ip::address_v4::any(), port), ec); + TEST_CHECK(!ec); + + fprintf(stderr, "fake_node::async_read_some\n"); + m_socket.async_receive(boost::asio::buffer(m_in_buffer) + , [&] (boost::system::error_code const& ec, size_t bytes_transferred) + { + fprintf(stderr, "fake_node::async_read_some callback. ec: %s transferred: %d\n" + , ec.message().c_str(), int(bytes_transferred)); + if (ec) return; + + lt::bdecode_node n; + boost::system::error_code err; + int const ret = bdecode(m_in_buffer, m_in_buffer + bytes_transferred + , n, err, nullptr, 10, 200); + TEST_EQUAL(ret, 0); + + // TODO: ideally we would validate the DHT message + m_tripped = true; + }); + } + + void close() + { + m_socket.close(); + } + + bool tripped() const { return m_tripped; } + +private: + + char m_in_buffer[300]; + + asio::io_service m_ios; + asio::ip::udp::socket m_socket; + bool m_tripped; + + std::vector m_send_buffer; +}; + template void check_accepted(std::array& test_peers , std::array expected) diff --git a/simulation/test_checking.cpp b/simulation/test_checking.cpp index b2a9f7f30..a44b853e3 100644 --- a/simulation/test_checking.cpp +++ b/simulation/test_checking.cpp @@ -69,7 +69,6 @@ void run_test(Setup const& setup, Test const& test) test(*ses); // shut down - ses->set_alert_notify([]{}); zombie = ses->abort(); ses.reset(); }); diff --git a/simulation/test_dht_bootstrap.cpp b/simulation/test_dht_bootstrap.cpp new file mode 100644 index 000000000..a56b33731 --- /dev/null +++ b/simulation/test_dht_bootstrap.cpp @@ -0,0 +1,97 @@ +/* + +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 "test.hpp" +#include "simulator/simulator.hpp" +#include "utils.hpp" +#include "fake_peer.hpp" // for fake_node +#include "libtorrent/time.hpp" +#include "settings.hpp" +#include "libtorrent/deadline_timer.hpp" +#include "setup_transfer.hpp" // for addr() + +namespace lt = libtorrent; +using namespace sim; + +struct sim_config : sim::default_config +{ + chrono::high_resolution_clock::duration hostname_lookup( + asio::ip::address const& requestor + , std::string hostname + , std::vector& result + , boost::system::error_code& ec) + { + if (hostname == "dht.libtorrent.org") + { + result.push_back(addr("10.0.0.10")); + return lt::duration_cast(chrono::milliseconds(100)); + } + return default_config::hostname_lookup(requestor, hostname, result, ec); + } +}; + +TORRENT_TEST(dht_bootstrap) +{ + using sim::asio::ip::address_v4; + sim_config network_cfg; + sim::simulation sim{network_cfg}; + + std::vector zombies; + + fake_node node(sim, "10.0.0.10", 25401); + + lt::settings_pack pack; + // we use 0 threads (disk I/O operations will be performed in the network + // thread) to be simulator friendly. + pack.set_int(lt::settings_pack::aio_threads, 0); + pack.set_bool(lt::settings_pack::enable_lsd, false); + pack.set_bool(lt::settings_pack::enable_upnp, false); + pack.set_bool(lt::settings_pack::enable_natpmp, false); + pack.set_bool(lt::settings_pack::enable_dht, true); + sim::asio::io_service ios(sim, addr("10.0.0.1")); + boost::shared_ptr ses = boost::make_shared(pack, ios); + + lt::deadline_timer timer(ios); + timer.expires_from_now(lt::seconds(10)); + timer.async_wait([&](lt::error_code const& ec) { + zombies.push_back(ses->abort()); + node.close(); + ses.reset(); + }); + + print_alerts(*ses); + + sim.run(); + + TEST_EQUAL(node.tripped(), true); +} + diff --git a/simulation/test_fast_extensions.cpp b/simulation/test_fast_extensions.cpp index 20eb9bba5..d8550ee4c 100644 --- a/simulation/test_fast_extensions.cpp +++ b/simulation/test_fast_extensions.cpp @@ -79,7 +79,6 @@ void run_fake_peer_test( sim::timer t(sim, lt::seconds(1) , [&](boost::system::error_code const&) { - ses->set_alert_notify([]{}); // shut down zombie = ses->abort(); diff --git a/simulation/test_ip_filter.cpp b/simulation/test_ip_filter.cpp index de5c815cf..d20cf681f 100644 --- a/simulation/test_ip_filter.cpp +++ b/simulation/test_ip_filter.cpp @@ -89,7 +89,6 @@ void run_test(Setup const& setup { test(*ses, test_peers); - ses->set_alert_notify([]{}); // shut down zombie = ses->abort(); diff --git a/simulation/test_optimistic_unchoke.cpp b/simulation/test_optimistic_unchoke.cpp index 3b7415a0c..76502c961 100644 --- a/simulation/test_optimistic_unchoke.cpp +++ b/simulation/test_optimistic_unchoke.cpp @@ -150,7 +150,6 @@ TORRENT_TEST(optimistic_unchoke) { p->abort(); } - ses->set_alert_notify([]{}); proxy = ses->abort(); ses.reset(); }); diff --git a/simulation/test_socks5.cpp b/simulation/test_socks5.cpp index 9e661c4e4..cc697d85b 100644 --- a/simulation/test_socks5.cpp +++ b/simulation/test_socks5.cpp @@ -94,7 +94,6 @@ void run_test(Setup const& setup { std::fprintf(stderr, "shutting down\n"); // shut down - ses->set_alert_notify([] {}); zombie = ses->abort(); ses.reset(); }); diff --git a/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 57e802f7b..b44c7fa02 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -354,7 +354,6 @@ TORRENT_TEST(ipv6_support) , [&ses,&zombie](boost::system::error_code const&) { zombie = ses->abort(); - ses->set_alert_notify([]{}); ses.reset(); }); @@ -429,7 +428,6 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 , [&ses,&zombie](boost::system::error_code const&) { zombie = ses->abort(); - ses->set_alert_notify([]{}); ses.reset(); }); diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index c4e09d517..fa8f8d40b 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -152,7 +152,6 @@ void run_test( int idx = 0; for (auto& s : ses) { - s->set_alert_notify([]{}); zombie[idx++] = s->abort(); s.reset(); } diff --git a/simulation/test_web_seed.cpp b/simulation/test_web_seed.cpp index 790069390..d03c11cc3 100644 --- a/simulation/test_web_seed.cpp +++ b/simulation/test_web_seed.cpp @@ -105,7 +105,6 @@ void run_test(Setup const& setup { fprintf(stderr, "shutting down\n"); // shut down - ses->set_alert_notify([] {}); zombie = ses->abort(); ses.reset(); }); diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index bb167f3dd..474e07a5f 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -544,7 +544,7 @@ namespace libtorrent { if (m_include_mtime) info["mtime"] = m_files.mtime(0); info["length"] = m_files.file_size(0); - int flags = m_files.file_flags(0); + int const flags = m_files.file_flags(0); if (flags & (file_storage::flag_pad_file | file_storage::flag_hidden | file_storage::flag_executable diff --git a/src/file_storage.cpp b/src/file_storage.cpp index 796cf65f6..1cc75a029 100644 --- a/src/file_storage.cpp +++ b/src/file_storage.cpp @@ -47,8 +47,10 @@ POSSIBILITY OF SUCH DAMAGE. #if defined(TORRENT_WINDOWS) || defined(TORRENT_OS2) #define TORRENT_SEPARATOR '\\' +#define TORRENT_SEPARATOR_STR "\\" #else #define TORRENT_SEPARATOR '/' +#define TORRENT_SEPARATOR_STR "/" #endif using namespace std::placeholders; @@ -561,10 +563,10 @@ namespace libtorrent , symlink_path); } - void file_storage::add_file_borrow(char const* filename, int filename_len - , std::string const& path, std::int64_t file_size - , std::uint32_t file_flags, char const* filehash - , std::int64_t mtime, string_view symlink_path) + void file_storage::add_file_borrow(char const* filename, int const filename_len + , std::string const& path, std::int64_t const file_size + , std::uint32_t const file_flags, char const* filehash + , std::int64_t const mtime, string_view symlink_path) { TORRENT_ASSERT_PRECOND(file_size >= 0); if (!has_parent_path(path)) @@ -599,10 +601,10 @@ namespace libtorrent e.size = file_size; e.offset = m_total_size; - e.pad_file = file_flags & file_storage::flag_pad_file; - e.hidden_attribute = file_flags & file_storage::flag_hidden; - e.executable_attribute = file_flags & file_storage::flag_executable; - e.symlink_attribute = file_flags & file_storage::flag_symlink; + e.pad_file = (file_flags & file_storage::flag_pad_file) != 0; + e.hidden_attribute = (file_flags & file_storage::flag_hidden) != 0; + e.executable_attribute = (file_flags & file_storage::flag_executable) != 0; + e.symlink_attribute = (file_flags & file_storage::flag_symlink) != 0; if (filehash) { @@ -988,8 +990,8 @@ namespace libtorrent if (best_match != i) { - int index = best_match - m_files.begin(); - int cur_index = i - m_files.begin(); + int const index = best_match - m_files.begin(); + int const cur_index = i - m_files.begin(); reorder_file(index, cur_index); i = m_files.begin() + cur_index; } @@ -1002,8 +1004,8 @@ namespace libtorrent // not piece-aligned and the file size exceeds the // limit, and it's not a padding file itself. // so add a padding file in front of it - int pad_size = alignment - (off % alignment); - + int const pad_size = alignment - (off % alignment); + // find the largest file that fits in pad_size std::vector::iterator best_match = m_files.end(); @@ -1088,7 +1090,8 @@ namespace libtorrent e.size = size; e.offset = offset; char name[30]; - std::snprintf(name, sizeof(name), ".____padding_file/%d", pad_file_counter); + std::snprintf(name, sizeof(name), ".pad" TORRENT_SEPARATOR_STR "%d" + , pad_file_counter); std::string path = combine_path(m_name, name); e.set_name(path.c_str()); e.pad_file = true; diff --git a/src/gzip.cpp b/src/gzip.cpp index 062824285..5a147f721 100644 --- a/src/gzip.cpp +++ b/src/gzip.cpp @@ -212,9 +212,9 @@ namespace libtorrent // start off with 4 kilobytes and grow // if needed - std::uint32_t destlen = 4096; + unsigned long destlen = 4096; int ret = 0; - std::uint32_t srclen = size - header_len; + unsigned long srclen = size - header_len; in += header_len; do diff --git a/src/puff.cpp b/src/puff.cpp index 8e81af001..7f48a5a88 100644 --- a/src/puff.cpp +++ b/src/puff.cpp @@ -1,8 +1,8 @@ /* * puff.c - * Copyright (C) 2002, 2003 Mark Adler + * Copyright (C) 2002-2013 Mark Adler * For conditions of distribution and use, see copyright notice in puff.h - * version 1.7, 3 Mar 2003 + * version 2.3, 21 Jan 2013 * * puff.c is a simple inflate written to be an unambiguous way to specify the * deflate format. It is not written for speed but rather simplicity. As a @@ -49,9 +49,9 @@ * - Fix fixed codes table error * - Provide a scanning mode for determining size of * uncompressed data - * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Jean-loup] + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] * - Add a puff.h file for the interface - * - Add braces in puff() for else do [Jean-loup] + * - Add braces in puff() for else do [Gailly] * - Use indexes instead of pointers for readability * 1.4 31 Mar 2002 - Simplify construct() code set check * - Fix some comments @@ -60,26 +60,33 @@ * 1.6 7 Aug 2002 - Minor format changes * 1.7 3 Mar 2003 - Added test code for distribution * - Added zlib-like license + * 1.8 9 Jan 2004 - Added some comments on no distance codes case + * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] + * - Catch missing end-of-block symbol error + * 2.0 25 Jul 2008 - Add #define to permit distance too far back + * - Add option in TEST code for puff to write the data + * - Add option in TEST code to skip input bytes + * - Allow TEST code to read from piped stdin + * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers + * - Avoid unsigned comparisons for even happier compilers + * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer] + * - Add const where appropriate [Oberhumer] + * - Split if's and ?'s for coverage testing + * - Break out test code to separate file + * - Move NIL to puff.h + * - Allow incomplete code only if single code length is 1 + * - Add full code coverage test to Makefile + * 2.3 21 Jan 2013 - Check for invalid code length codes in dynamic blocks */ -/* -note by Arvid Norberg. -This file was turned into a .cpp file in order to -be able to take advantage of boost's cstdint.hpp file -All "short" has been replaced with std::int16_t -and all "long" with std::int32_t according to the -type width assuptions in the comment above. -*/ - // this whole file is just preserved and warnings are suppressed #include "libtorrent/aux_/disable_warnings_push.hpp" -#include /* for setjmp(), longjmp(), and jmp_buf */ -#include /* for types with size guarantees */ -#include "libtorrent/puff.hpp" /* prototype for puff() */ +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include /* for NULL */ +#include "puff.hpp" /* prototype for puff() */ #define local static /* for local function definitions */ -#define NIL ((unsigned char *)0) /* for no output option */ /* * Maximums for allocations and loops. It is not useful to change these -- @@ -95,13 +102,13 @@ type width assuptions in the comment above. struct state { /* output state */ unsigned char *out; /* output buffer */ - std::uint32_t outlen; /* available space at out */ - std::uint32_t outcnt; /* bytes written to out so far */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ /* input state */ - const unsigned char *in; /* input buffer */ - std::uint32_t inlen; /* available input at in */ - std::uint32_t incnt; /* bytes read so far */ + const unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ int bitbuf; /* bit buffer */ int bitcnt; /* number of bits in bit buffer */ @@ -122,22 +129,23 @@ struct state { */ local int bits(struct state *s, int need) { - std::int32_t val; /* bit accumulator (can use up to 20 bits) */ + long val; /* bit accumulator (can use up to 20 bits) */ /* load at least need bits into val */ val = s->bitbuf; while (s->bitcnt < need) { - if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ - val |= (std::int32_t)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + val |= long(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ s->bitcnt += 8; } /* drop need bits and update buffer, always zero to seven bits left */ - s->bitbuf = (int)(val >> need); + s->bitbuf = int(val >> need); s->bitcnt -= need; /* return need bits, zeroing the bits above that */ - return (int)(val & ((1L << need) - 1)); + return int(val & ((1L << need) - 1)); } /* @@ -166,7 +174,8 @@ local int stored(struct state *s) s->bitcnt = 0; /* get length and check against its one's complement */ - if (s->incnt + 4 > s->inlen) return 2; /* not enough input */ + if (s->incnt + 4 > s->inlen) + return 2; /* not enough input */ len = s->in[s->incnt++]; len |= s->in[s->incnt++] << 8; if (s->in[s->incnt++] != (~len & 0xff) || @@ -174,8 +183,9 @@ local int stored(struct state *s) return -2; /* didn't match complement! */ /* copy len bytes from in to out */ - if (s->incnt + len > s->inlen) return 2; /* not enough input */ - if (s->out != NIL) { + if (s->incnt + len > s->inlen) + return 2; /* not enough input */ + if (s->out != NULL) { if (s->outcnt + len > s->outlen) return 1; /* not enough output space */ while (len--) @@ -198,15 +208,15 @@ local int stored(struct state *s) * seen in the function decode() below. */ struct huffman { - std::int16_t *count; /* number of symbols of each length */ - std::int16_t *symbol; /* canonically ordered symbols */ + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ }; /* * Decode a code from the stream s using huffman table h. Return the symbol or * a negative value if there is an error. If all of the lengths are zero, i.e. * an empty code, or if the code is incomplete and an invalid code is received, - * then -9 is returned after reading MAXBITS bits. + * then -10 is returned after reading MAXBITS bits. * * Format notes: * @@ -226,7 +236,7 @@ struct huffman { * in the deflate format. See the format notes for fixed() and dynamic(). */ #ifdef SLOW -local int decode(struct state *s, struct huffman *h) +local int decode(struct state *s, const struct huffman *h) { int len; /* current number of bits in code */ int code; /* len bits being decoded */ @@ -238,14 +248,14 @@ local int decode(struct state *s, struct huffman *h) for (len = 1; len <= MAXBITS; len++) { code |= bits(s, 1); /* get next bit */ count = h->count[len]; - if (code < first + count) /* if length len, return symbol */ + if (code - count < first) /* if length len, return symbol */ return h->symbol[index + (code - first)]; index += count; /* else update for next length */ first += count; first <<= 1; code <<= 1; } - return -9; /* ran out of codes */ + return -10; /* ran out of codes */ } /* @@ -254,7 +264,7 @@ local int decode(struct state *s, struct huffman *h) * a few percent larger. */ #else /* !SLOW */ -local int decode(struct state *s, struct huffman *h) +local int decode(struct state *s, const struct huffman *h) { int len; /* current number of bits in code */ int code; /* len bits being decoded */ @@ -263,7 +273,7 @@ local int decode(struct state *s, struct huffman *h) int index; /* index of first code of length len in symbol table */ int bitbuf; /* bits from stream */ int left; /* bits left in next or left to process */ - std::int16_t *next; /* next number of codes */ + short *next; /* next number of codes */ bitbuf = s->bitbuf; left = s->bitcnt; @@ -275,7 +285,7 @@ local int decode(struct state *s, struct huffman *h) code |= bitbuf & 1; bitbuf >>= 1; count = *next++; - if (code < first + count) { /* if length len, return symbol */ + if (code - count < first) { /* if length len, return symbol */ s->bitbuf = bitbuf; s->bitcnt = (s->bitcnt - len) & 7; return h->symbol[index + (code - first)]; @@ -287,12 +297,15 @@ local int decode(struct state *s, struct huffman *h) len++; } left = (MAXBITS+1) - len; - if (left == 0) break; - if (s->incnt == s->inlen) longjmp(s->env, 1); /* out of input */ + if (left == 0) + break; + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ bitbuf = s->in[s->incnt++]; - if (left > 8) left = 8; + if (left > 8) + left = 8; } - return -9; /* ran out of codes */ + return -10; /* ran out of codes */ } #endif /* SLOW */ @@ -328,12 +341,12 @@ local int decode(struct state *s, struct huffman *h) * - Within a given code length, the symbols are kept in ascending order for * the code bits definition. */ -local int construct(struct huffman *h, std::int16_t *length, int n) +local int construct(struct huffman *h, const short *length, int n) { int symbol; /* current symbol when stepping through length[] */ int len; /* current length when stepping through h->count[] */ int left; /* number of possible codes left of current length */ - std::int16_t offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ /* count number of codes of each length */ for (len = 0; len <= MAXBITS; len++) @@ -348,7 +361,8 @@ local int construct(struct huffman *h, std::int16_t *length, int n) for (len = 1; len <= MAXBITS; len++) { left <<= 1; /* one more bit, double codes left */ left -= h->count[len]; /* deduct count from possible codes */ - if (left < 0) return left; /* over-subscribed--return negative */ + if (left < 0) + return left; /* over-subscribed--return negative */ } /* left > 0 means incomplete */ /* generate offsets into symbol table for each length for sorting */ @@ -424,23 +438,23 @@ local int construct(struct huffman *h, std::int16_t *length, int n) * defined to do the wrong thing in this case. */ local int codes(struct state *s, - struct huffman *lencode, - struct huffman *distcode) + const struct huffman *lencode, + const struct huffman *distcode) { int symbol; /* decoded symbol */ int len; /* length for copy */ unsigned dist; /* distance for copy */ - static const std::int16_t lens[29] = { /* Size base for length codes 257..285 */ + static const short lens[29] = { /* Size base for length codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; - static const std::int16_t lext[29] = { /* Extra bits for length codes 257..285 */ + static const short lext[29] = { /* Extra bits for length codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; - static const std::int16_t dists[30] = { /* Offset base for distance codes 0..29 */ + static const short dists[30] = { /* Offset base for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; - static const std::int16_t dext[30] = { /* Extra bits for distance codes 0..29 */ + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; @@ -448,11 +462,13 @@ local int codes(struct state *s, /* decode literals and length/distance pairs */ do { symbol = decode(s, lencode); - if (symbol < 0) return symbol; /* invalid symbol */ + if (symbol < 0) + return symbol; /* invalid symbol */ if (symbol < 256) { /* literal: symbol is the byte */ /* write out the literal */ - if (s->out != NIL) { - if (s->outcnt == s->outlen) return 1; + if (s->out != NULL) { + if (s->outcnt == s->outlen) + return 1; s->out[s->outcnt] = symbol; } s->outcnt++; @@ -460,21 +476,31 @@ local int codes(struct state *s, else if (symbol > 256) { /* length */ /* get and compute length */ symbol -= 257; - if (symbol >= 29) return -9; /* invalid fixed code */ + if (symbol >= 29) + return -10; /* invalid fixed code */ len = lens[symbol] + bits(s, lext[symbol]); /* get and check distance */ symbol = decode(s, distcode); - if (symbol < 0) return symbol; /* invalid symbol */ + if (symbol < 0) + return symbol; /* invalid symbol */ dist = dists[symbol] + bits(s, dext[symbol]); +#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (dist > s->outcnt) - return -10; /* distance too far back */ + return -11; /* distance too far back */ +#endif /* copy length bytes from distance bytes back */ - if (s->out != NIL) { - if (s->outcnt + len > s->outlen) return 1; + if (s->out != NULL) { + if (s->outcnt + len > s->outlen) + return 1; while (len--) { - s->out[s->outcnt] = s->out[s->outcnt - dist]; + s->out[s->outcnt] = +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + dist > s->outcnt ? + 0 : +#endif + s->out[s->outcnt - dist]; s->outcnt++; } } @@ -514,15 +540,20 @@ local int codes(struct state *s, local int fixed(struct state *s) { static int virgin = 1; - static std::int16_t lencnt[MAXBITS+1], lensym[FIXLCODES]; - static std::int16_t distcnt[MAXBITS+1], distsym[MAXDCODES]; - static struct huffman lencode = {lencnt, lensym}; - static struct huffman distcode = {distcnt, distsym}; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode, distcode; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { int symbol; - std::int16_t lengths[FIXLCODES]; + short lengths[FIXLCODES]; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; /* literal/length table */ for (symbol = 0; symbol < 144; symbol++) @@ -590,6 +621,9 @@ local int fixed(struct state *s) * block is fewer bits), but it is allowed by the format. So incomplete * literal/length codes of one symbol should also be permitted. * + * - If there are only literal codes and no lengths, then there are no distance + * codes. This is represented by one distance code with zero bits. + * * - The list of up to 286 length/literal lengths and up to 30 distance lengths * are themselves compressed using Huffman codes and run-length encoding. In * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means @@ -637,14 +671,19 @@ local int dynamic(struct state *s) int nlen, ndist, ncode; /* number of lengths in descriptor */ int index; /* index of lengths[] */ int err; /* construct() return value */ - std::int16_t lengths[MAXCODES]; /* descriptor code lengths */ - std::int16_t lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ - std::int16_t distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ - struct huffman lencode = {lencnt, lensym}; /* length code */ - struct huffman distcode = {distcnt, distsym}; /* distance code */ - static const std::int16_t order[19] = /* permutation of code length codes */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode, distcode; /* length and distance codes */ + static const short order[19] = /* permutation of code length codes */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + /* get number of lengths in each table, check lengths */ nlen = bits(s, 5) + 257; ndist = bits(s, 5) + 1; @@ -660,7 +699,8 @@ local int dynamic(struct state *s) /* build huffman table for code lengths codes (use lencode temporarily) */ err = construct(&lencode, lengths, 19); - if (err != 0) return -4; /* require complete code set here */ + if (err != 0) /* require complete code set here */ + return -4; /* read length/literal and distance code length tables */ index = 0; @@ -668,13 +708,16 @@ local int dynamic(struct state *s) int symbol; /* decoded value */ symbol = decode(s, &lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ if (symbol < 16) /* length in 0..15 */ lengths[index++] = symbol; else { /* repeat instruction */ int len = 0; /* last length to repeat */ /* assume repeating zeros */ if (symbol == 16) { /* repeat last length 3..6 times */ - if (index == 0) return -5; /* no last length! */ + if (index == 0) + return -5; /* no last length! */ len = lengths[index - 1]; /* last length */ symbol = 3 + bits(s, 2); } @@ -689,15 +732,19 @@ local int dynamic(struct state *s) } } + /* check for end-of-block code -- there better be one! */ + if (lengths[256] == 0) + return -9; + /* build huffman table for literal/length codes */ err = construct(&lencode, lengths, nlen); - if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1)) - return -7; /* only allow incomplete codes if just one code */ + if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) + return -7; /* incomplete code ok only for single length 1 code */ /* build huffman table for distance codes */ err = construct(&distcode, lengths + nlen, ndist); - if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1)) - return -8; /* only allow incomplete codes if just one code */ + if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) + return -8; /* incomplete code ok only for single length 1 code */ /* decode data until end-of-block code */ return codes(s, &lencode, &distcode); @@ -733,8 +780,9 @@ local int dynamic(struct state *s) * -6: dynamic block code description: repeat more than specified lengths * -7: dynamic block code description: invalid literal/length code lengths * -8: dynamic block code description: invalid distance code lengths - * -9: invalid literal/length or distance code in fixed or dynamic block - * -10: distance is too far back in fixed or dynamic block + * -9: dynamic block code description: missing end-of-block code + * -10: invalid literal/length or distance code in fixed or dynamic block + * -11: distance is too far back in fixed or dynamic block * * Format notes: * @@ -747,11 +795,12 @@ local int dynamic(struct state *s) * expected values to check. */ int puff(unsigned char *dest, /* pointer to destination pointer */ - std::uint32_t *destlen, /* amount of output space */ - const unsigned char *source, /* pointer to source data pointer */ - std::uint32_t *sourcelen) /* amount of input available */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ { struct state s; /* input/output state */ + int last, type; /* block information */ int err; /* return value */ /* initialize output state */ @@ -771,15 +820,18 @@ int puff(unsigned char *dest, /* pointer to destination pointer */ err = 2; /* then skip do-loop, return error */ else { /* process blocks until last block or error */ - int last = 0; do { - last = bits(&s, 1); /* one if last block */ - int type = bits(&s, 2); /* block type 0..3 */ - err = type == 0 ? stored(&s) : - (type == 1 ? fixed(&s) : - (type == 2 ? dynamic(&s) : - -1)); /* type == 3, invalid */ - if (err != 0) break; /* return with error */ + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? + stored(&s) : + (type == 1 ? + fixed(&s) : + (type == 2 ? + dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) + break; /* return with error */ } while (!last); } @@ -790,60 +842,3 @@ int puff(unsigned char *dest, /* pointer to destination pointer */ } return err; } - -#ifdef TEST -/* Example of how to use puff() */ -#include -#include -#include -#include - -local unsigned char *yank(char *name, std::uint32_t *len) -{ - std::uint32_t size; - unsigned char *buf; - FILE *in; - struct stat s; - - *len = 0; - if (stat(name, &s)) return nullptr; - if ((s.st_mode & S_IFMT) != S_IFREG) return nullptr; - size = (std::uint32_t)(s.st_size); - if (size == 0 || (off_t)size != s.st_size) return nullptr; - in = fopen(name, "r"); - if (in == nullptr) return nullptr; - buf = malloc(size); - if (buf != nullptr && fread(buf, 1, size, in) != size) { - free(buf); - buf = nullptr; - } - fclose(in); - *len = size; - return buf; -} - -int main(int argc, char **argv) -{ - int ret; - unsigned char *source; - std::uint32_t len, sourcelen, destlen; - - if (argc < 2) return 2; - source = yank(argv[1], &len); - if (source == nullptr) return 2; - sourcelen = len; - ret = puff(NIL, &destlen, source, &sourcelen); - if (ret) - std::printf("puff() failed with return code %d\n", ret); - else { - std::printf("puff() succeeded uncompressing %lu bytes\n", destlen); - if (sourcelen < len) std::printf("%lu compressed bytes unused\n", - len - sourcelen); - } - free(source); - return ret; -} -#endif - -#include "libtorrent/aux_/disable_warnings_pop.hpp" - diff --git a/src/session.cpp b/src/session.cpp index 28d7642a2..11e978178 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -378,6 +378,14 @@ namespace libtorrent m_thread->join(); } + session_proxy session::abort() + { + // stop calling the alert notify function now, to avoid it thinking the + // session is still alive + m_impl->alerts().set_notify_function(std::function()); + return session_proxy(m_io_service, m_thread, m_impl); + } + #ifndef TORRENT_NO_DEPRECATE session_settings::session_settings(std::string const& user_agent_) { diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 744d193b4..1ac0ac001 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -556,6 +556,7 @@ namespace aux { update_lsd(); update_dht(); update_peer_fingerprint(); + update_dht_bootstrap_nodes(); #ifndef TORRENT_DISABLE_DHT update_dht_announce_interval(); #endif @@ -839,6 +840,10 @@ namespace aux { session_log(" *** ABORT CALLED ***"); #endif + // at this point we cannot call the notify function anymore, since the + // session will become invalid. + m_alerts.set_notify_function(std::function()); + // this will cancel requests that are not critical for shutting down // cleanly. i.e. essentially tracker hostname lookups that we're not // about to send event=stopped to @@ -5240,6 +5245,20 @@ namespace aux { } } + void session_impl::update_dht_bootstrap_nodes() + { +#ifndef TORRENT_DISABLE_DHT + std::string const& node_list = m_settings.get_str(settings_pack::dht_bootstrap_nodes); + std::vector > nodes; + parse_comma_separated_string_port(node_list, nodes); + + for (int i = 0; i < nodes.size(); ++i) + { + add_dht_router(nodes[i]); + } +#endif + } + void session_impl::update_count_slow() { error_code ec; diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index f5370d754..c73d443b2 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -139,7 +139,8 @@ namespace libtorrent SET_NOPREV(proxy_username, "", &session_impl::update_proxy), SET_NOPREV(proxy_password, "", &session_impl::update_proxy), SET_NOPREV(i2p_hostname, "", &session_impl::update_i2p_bridge), - SET_NOPREV(peer_fingerprint, "-LT1200-", &session_impl::update_peer_fingerprint) + SET_NOPREV(peer_fingerprint, "-LT1200-", &session_impl::update_peer_fingerprint), + SET_NOPREV(dht_bootstrap_nodes, "dht.libtorrent.org:25401", &session_impl::update_dht_bootstrap_nodes) }; bool_setting_entry_t bool_settings[settings_pack::num_bool_settings] = diff --git a/src/string_util.cpp b/src/string_util.cpp index 1beee3c6e..cb031635e 100644 --- a/src/string_util.cpp +++ b/src/string_util.cpp @@ -295,6 +295,51 @@ namespace libtorrent } } + // this parses the string that's used as the listen_interfaces setting. + // it is a comma-separated list of IP or device names with ports. For + // example: "eth0:6881,eth1:6881" or "127.0.0.1:6881" + void parse_comma_separated_string_port(std::string const& in + , std::vector >& out) + { + out.clear(); + + std::string::size_type start = 0; + std::string::size_type end = 0; + + while (start < in.size()) + { + // skip leading spaces + while (start < in.size() + && is_space(in[start])) + ++start; + + end = in.find_first_of(',', start); + if (end == std::string::npos) end = in.size(); + + std::string::size_type colon = in.find_last_of(':', end); + + if (colon != std::string::npos && colon > start) + { + int port = atoi(in.substr(colon + 1, end - colon - 1).c_str()); + + // skip trailing spaces + std::string::size_type soft_end = colon; + while (soft_end > start + && is_space(in[soft_end-1])) + --soft_end; + + // in case this is an IPv6 address, strip off the square brackets + // to make it more easily parseable into an ip::address + if (in[start] == '[') ++start; + if (soft_end > start && in[soft_end-1] == ']') --soft_end; + + out.push_back(std::make_pair(in.substr(start, soft_end - start), port)); + } + + start = end + 1; + } + } + void parse_comma_separated_string(std::string const& in, std::vector& out) { out.clear(); diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 0f29c3de2..3cbac33d3 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -375,6 +375,46 @@ namespace libtorrent namespace { + boost::uint32_t get_file_attributes(bdecode_node const& dict) + { + boost::uint32_t file_flags = 0; + bdecode_node attr = dict.dict_find_string("attr"); + if (attr) + { + for (int i = 0; i < attr.string_length(); ++i) + { + switch (attr.string_ptr()[i]) + { + case 'l': file_flags |= file_storage::flag_symlink; break; + case 'x': file_flags |= file_storage::flag_executable; break; + case 'h': file_flags |= file_storage::flag_hidden; break; + case 'p': file_flags |= file_storage::flag_pad_file; break; + } + } + } + return file_flags; + } + + // iterates an array of strings and returns the sum of the lengths of all + // strings + one additional character per entry (to account for the presumed + // forward- or backslash to seaprate directory entries) + int path_length(bdecode_node const& p, error_code& ec) + { + int ret = 0; + int const len = p.list_size(); + for (int i = 0; i < len; ++i) + { + bdecode_node e = p.list_at(i); + if (e.type() != bdecode_node::string_t) + { + ec = errors::torrent_invalid_name; + return -1; + } + ret += e.string_length(); + } + return ret + len; + } + // 'top_level' is extracting the file for a single-file torrent. The // distinction is that the filename is found in "name" rather than // "path" @@ -382,17 +422,24 @@ namespace libtorrent // torrent, in which case it's empty. bool extract_single_file(bdecode_node const& dict, file_storage& files , std::string const& root_dir, ptrdiff_t info_ptr_diff, bool top_level - , error_code& ec) + , int& pad_file_cnt, error_code& ec) { if (dict.type() != bdecode_node::dict_t) return false; - std::int64_t file_size = dict.dict_find_int_value("length", -1); - if (file_size < 0) + + boost::uint32_t file_flags = get_file_attributes(dict); + + // symlinks have an implied "size" of zero. i.e. they use up 0 bytes of + // the torrent payload space + boost::int64_t const file_size = (file_flags & file_storage::flag_symlink) + ? 0 + : dict.dict_find_int_value("length", -1); + if (file_size < 0 ) { ec = errors::torrent_invalid_length; return false; } - std::int64_t mtime = dict.dict_find_int_value("mtime", 0); + boost::int64_t const mtime = dict.dict_find_int_value("mtime", 0); std::string path = root_dir; std::string path_element; @@ -419,71 +466,62 @@ namespace libtorrent { bdecode_node p = dict.dict_find_list("path.utf-8"); if (!p) p = dict.dict_find_list("path"); - if (!p || p.list_size() == 0) + + if (p && p.list_size() > 0) + { + int const preallocate = path.size() + path_length(p, ec); + if (ec) return false; + path.reserve(preallocate); + + for (int i = 0, end(p.list_size()); i < end; ++i) + { + bdecode_node e = p.list_at(i); + if (i == end - 1) + { + filename = e.string_ptr() + info_ptr_diff; + filename_len = e.string_length(); + } + sanitize_append_path_element(path, e.string_value()); + } + } + else if (file_flags & file_storage::flag_pad_file) + { + // pad files don't need a path element, we'll just store them + // under the .pad directory + char cnt[10]; + snprintf(cnt, sizeof(cnt), "%d", pad_file_cnt); + path = combine_path(".pad", cnt); + ++pad_file_cnt; + } + else { ec = errors::torrent_missing_name; return false; } - - int preallocate = int(path.size()); - for (int i = 0, end(p.list_size()); i < end; ++i) - { - bdecode_node e = p.list_at(i); - if (e.type() != bdecode_node::string_t) - { - ec = errors::torrent_missing_name; - return false; - } - preallocate += e.string_length() + 1; - } - path.reserve(preallocate); - - for (int i = 0, end(p.list_size()); i < end; ++i) - { - bdecode_node e = p.list_at(i); - if (i == end - 1) - { - filename = e.string_ptr() + info_ptr_diff; - filename_len = e.string_length(); - } - sanitize_append_path_element(path, e.string_value()); - } } // bitcomet pad file - std::uint32_t file_flags = 0; if (path.find("_____padding_file_") != std::string::npos) file_flags = file_storage::flag_pad_file; - bdecode_node attr = dict.dict_find_string("attr"); - if (attr) - { - for (int i = 0; i < attr.string_length(); ++i) - { - switch (attr.string_ptr()[i]) - { - case 'l': file_flags |= file_storage::flag_symlink; file_size = 0; break; - case 'x': file_flags |= file_storage::flag_executable; break; - case 'h': file_flags |= file_storage::flag_hidden; break; - case 'p': file_flags |= file_storage::flag_pad_file; break; - } - } - } - bdecode_node fh = dict.dict_find_string("sha1"); char const* filehash = nullptr; if (fh && fh.string_length() == 20) filehash = fh.string_ptr() + info_ptr_diff; std::string symlink_path; - bdecode_node s_p = dict.dict_find("symlink path"); - if (s_p && s_p.type() == bdecode_node::list_t - && (file_flags & file_storage::flag_symlink)) + if (file_flags & file_storage::flag_symlink) { - for (int i = 0, end(s_p.list_size()); i < end; ++i) + if (bdecode_node s_p = dict.dict_find_list("symlink path")) { - auto pe = s_p.list_at(i).string_value(); - append_path(symlink_path, pe); + int const preallocate = path_length(s_p, ec); + if (ec) return false; + symlink_path.reserve(preallocate); + for (int i = 0, end(s_p.list_size()); i < end; ++i) + { + auto pe = s_p.list_at(i).string_value(); + sanitize_append_path_element(symlink_path, pe); + } } } else @@ -557,10 +595,12 @@ namespace libtorrent } target.reserve(list.list_size()); + // this is the counter used to name pad files + int pad_file_cnt = 0; for (int i = 0, end(list.list_size()); i < end; ++i) { if (!extract_single_file(list.list_at(i), target, root_dir - , info_ptr_diff, false, ec)) + , info_ptr_diff, false, pad_file_cnt, ec)) return false; } return true; @@ -1095,7 +1135,9 @@ namespace libtorrent { // if there's no list of files, there has to be a length // field. - if (!extract_single_file(info, files, "", info_ptr_diff, true, ec)) + // this is the counter used to name pad files + int pad_file_cnt = 0; + if (!extract_single_file(info, files, "", info_ptr_diff, true, pad_file_cnt, ec)) return false; m_flags &= ~multifile; diff --git a/test/Jamfile b/test/Jamfile index 2e92095c7..a5149fa22 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -113,7 +113,6 @@ test-suite libtorrent : test_sliding_average.cpp test_socket_io.cpp # test_random.cpp - test_gzip.cpp test_part_file.cpp test_peer_list.cpp test_torrent_info.cpp @@ -155,6 +154,7 @@ test-suite libtorrent : [ run test_bitfield.cpp ] [ run test_crc32.cpp ] [ run test_ffs.cpp ] + [ run test_gzip.cpp ] [ run test_receive_buffer.cpp ] [ run test_alert_manager.cpp ] [ run test_magnet.cpp ] @@ -225,6 +225,7 @@ alias win-tests : test_resume test_tracker test_checking + test_gzip test_piece_picker test_ffs test_session_params diff --git a/test/Makefile.am b/test/Makefile.am index 7843043c7..f8b5ef2fb 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -75,6 +75,7 @@ EXTRA_DIST = Jamfile \ test_torrents/invalid_pieces.torrent \ test_torrents/invalid_root_hash.torrent \ test_torrents/invalid_root_hash2.torrent \ + test_torrents/invalid_symlink.torrent \ test_torrents/long_name.torrent \ test_torrents/missing_path_list.torrent \ test_torrents/missing_piece_len.torrent \ @@ -84,6 +85,7 @@ EXTRA_DIST = Jamfile \ test_torrents/no_creation_date.torrent \ test_torrents/no_name.torrent \ test_torrents/pad_file.torrent \ + test_torrents/pad_file_no_path.torrent \ test_torrents/parent_path.torrent \ test_torrents/root_hash.torrent \ test_torrents/sample.torrent \ @@ -93,6 +95,7 @@ EXTRA_DIST = Jamfile \ test_torrents/slash_path3.torrent \ test_torrents/string.torrent \ test_torrents/symlink1.torrent \ + test_torrents/symlink_zero_size.torrent \ test_torrents/unaligned_pieces.torrent \ test_torrents/unordered.torrent \ test_torrents/url_list.torrent \ @@ -112,6 +115,7 @@ EXTRA_DIST = Jamfile \ mutable_test_torrents/test3.torrent \ mutable_test_torrents/test3_pad_files.torrent \ zeroes.gz \ + corrupt.gz \ utf8_test.txt \ web_server.py \ socks.py \ diff --git a/test/corrupt.gz b/test/corrupt.gz new file mode 100644 index 000000000..9ed0b14bf Binary files /dev/null and b/test/corrupt.gz differ diff --git a/test/settings.cpp b/test/settings.cpp index 9ea20f42e..614c732fd 100644 --- a/test/settings.cpp +++ b/test/settings.cpp @@ -49,6 +49,7 @@ libtorrent::settings_pack settings() pack.set_bool(settings_pack::enable_natpmp, false); pack.set_bool(settings_pack::enable_upnp, false); pack.set_bool(settings_pack::enable_dht, false); + pack.set_str(settings_pack::dht_bootstrap_nodes, ""); pack.set_bool(settings_pack::prefer_rc4, false); pack.set_int(settings_pack::in_enc_policy, settings_pack::pe_disabled); diff --git a/test/test_dht_storage.cpp b/test/test_dht_storage.cpp index d925768f0..f2b7afeea 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -209,6 +209,7 @@ TORRENT_TEST(set_custom) g_storage_constructor_invoked = false; settings_pack p; p.set_bool(settings_pack::enable_dht, false); + p.set_str(settings_pack::dht_bootstrap_nodes, ""); lt::session ses(p); TEST_EQUAL(g_storage_constructor_invoked, false); @@ -217,6 +218,7 @@ TORRENT_TEST(set_custom) ses.set_dht_storage(dht_custom_storage_constructor); p.set_bool(settings_pack::enable_dht, true); + p.set_str(settings_pack::dht_bootstrap_nodes, ""); ses.apply_settings(p); // async with dispatch TEST_CHECK(ses.is_dht_running()); TEST_EQUAL(g_storage_constructor_invoked, true); @@ -227,6 +229,7 @@ TORRENT_TEST(default_set_custom) g_storage_constructor_invoked = false; settings_pack p; p.set_bool(settings_pack::enable_dht, true); + p.set_str(settings_pack::dht_bootstrap_nodes, ""); lt::session ses(p); TEST_CHECK(ses.is_dht_running()); diff --git a/test/test_direct_dht.cpp b/test/test_direct_dht.cpp index cfae965c6..759c40ea0 100644 --- a/test/test_direct_dht.cpp +++ b/test/test_direct_dht.cpp @@ -95,6 +95,7 @@ TORRENT_TEST(direct_dht_request) sp.set_bool(settings_pack::enable_lsd, false); sp.set_bool(settings_pack::enable_natpmp, false); sp.set_bool(settings_pack::enable_upnp, false); + sp.set_str(settings_pack::dht_bootstrap_nodes, ""); sp.set_int(settings_pack::max_retry_port_bind, 800); sp.set_str(settings_pack::listen_interfaces, "127.0.0.1:42434"); lt::session responder(sp, 0); @@ -117,6 +118,7 @@ TORRENT_TEST(direct_dht_request) bdecode_node response = ra->response(); TEST_EQUAL(ra->addr.address(), address::from_string("127.0.0.1")); TEST_EQUAL(ra->addr.port(), responder.listen_port()); + TEST_EQUAL(response.type(), bdecode_node::dict_t); TEST_EQUAL(response.dict_find_dict("r").dict_find_int_value("good"), 1); TEST_EQUAL(ra->userdata, (void*)12345); } diff --git a/test/test_gzip.cpp b/test/test_gzip.cpp index a6b75e4b1..96b9a3b0e 100644 --- a/test/test_gzip.cpp +++ b/test/test_gzip.cpp @@ -38,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. using namespace libtorrent; -TORRENT_TEST(gzip) +TORRENT_TEST(zeroes) { std::vector zipped; error_code ec; @@ -59,3 +59,19 @@ TORRENT_TEST(gzip) TEST_EQUAL(inflated[i], 0); } +TORRENT_TEST(corrupt) +{ + std::vector zipped; + error_code ec; + load_file(combine_path("..", "corrupt.gz"), zipped, ec, 1000000); + if (ec) fprintf(stderr, "failed to open file: (%d) %s\n", ec.value() + , ec.message().c_str()); + TEST_CHECK(!ec); + + std::vector inflated; + inflate_gzip(&zipped[0], zipped.size(), inflated, 1000000, ec); + + // we expect this to fail + TEST_CHECK(ec); +} + diff --git a/test/test_ip_filter.cpp b/test/test_ip_filter.cpp index ee87e8c12..38aa9041e 100644 --- a/test/test_ip_filter.cpp +++ b/test/test_ip_filter.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "test.hpp" +#include "settings.hpp" #include "libtorrent/socket_io.hpp" #include "libtorrent/session.hpp" @@ -90,7 +91,7 @@ void test_rules_invariant(std::vector > const& r, ip_filter const& f TORRENT_TEST(session_get_ip_filter) { using namespace libtorrent; - session ses; + session ses(settings()); ip_filter const& ipf = ses.get_ip_filter(); #if TORRENT_USE_IPV6 TEST_EQUAL(std::get<0>(ipf.export_filter()).size(), 1); diff --git a/test/test_magnet.cpp b/test/test_magnet.cpp index 37c552129..10c0e8322 100644 --- a/test/test_magnet.cpp +++ b/test/test_magnet.cpp @@ -39,13 +39,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" // for announce_entry #include "libtorrent/announce_entry.hpp" #include "libtorrent/hex.hpp" // to_hex +#include "settings.hpp" using namespace libtorrent; namespace lt = libtorrent; void test_remove_url(std::string url) { - lt::session s; + lt::session s(settings()); add_torrent_params p; p.flags &= ~add_torrent_params::flag_paused; p.flags &= ~add_torrent_params::flag_auto_managed; @@ -79,7 +80,7 @@ TORRENT_TEST(magnet) session_proxy p2; // test session state load/restore - settings_pack pack; + settings_pack pack = settings(); pack.set_str(settings_pack::user_agent, "test"); pack.set_int(settings_pack::tracker_receive_timeout, 1234); pack.set_int(settings_pack::file_pool_size, 543); @@ -181,7 +182,7 @@ TORRENT_TEST(magnet) TEST_EQUAL(aux::to_hex(ih), "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"); p1 = s->abort(); - s.reset(new lt::session()); + s.reset(new lt::session(settings())); std::vector buf; bencode(std::back_inserter(buf), session_state); diff --git a/test/test_priority.cpp b/test/test_priority.cpp index 945bee1df..0c0de1bc4 100644 --- a/test/test_priority.cpp +++ b/test/test_priority.cpp @@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" +#include "settings.hpp" #include #include @@ -386,7 +387,7 @@ done: TORRENT_TEST(priority) { using namespace libtorrent; - settings_pack p; + settings_pack p = settings(); test_transfer(p); cleanup(); } @@ -405,7 +406,7 @@ TORRENT_TEST(priority_deprecated) // yet TORRENT_TEST(no_metadata_file_prio) { - settings_pack pack; + settings_pack pack = settings(); lt::session ses(pack); add_torrent_params addp; @@ -425,7 +426,7 @@ TORRENT_TEST(no_metadata_file_prio) TORRENT_TEST(no_metadata_piece_prio) { - settings_pack pack; + settings_pack pack = settings(); lt::session ses(pack); add_torrent_params addp; diff --git a/test/test_privacy.cpp b/test/test_privacy.cpp index 9dbf5e1d4..dc0362b9e 100644 --- a/test/test_privacy.cpp +++ b/test/test_privacy.cpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "peer_server.hpp" #include "udp_tracker.hpp" #include "test_utils.hpp" +#include "settings.hpp" #include "libtorrent/alert.hpp" #include "libtorrent/random.hpp" @@ -101,7 +102,7 @@ session_proxy test_proxy(settings_pack::proxy_type_t proxy_type, int flags) & ~alert::progress_notification & ~alert::stats_notification; - settings_pack sett; + settings_pack sett = settings(); sett.set_int(settings_pack::stop_tracker_timeout, 2); sett.set_int(settings_pack::tracker_completion_timeout, 2); sett.set_int(settings_pack::tracker_receive_timeout, 2); diff --git a/test/test_resume.cpp b/test/test_resume.cpp index 859398927..2b8621b72 100644 --- a/test/test_resume.cpp +++ b/test/test_resume.cpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "settings.hpp" #include "setup_transfer.hpp" +#include "settings.hpp" using namespace libtorrent; namespace lt = libtorrent; @@ -199,8 +200,7 @@ void default_tests(torrent_status const& s) void test_piece_priorities(bool test_deprecated = false) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -276,7 +276,7 @@ TORRENT_TEST(piece_priorities) #ifndef TORRENT_NO_DEPRECATE TORRENT_TEST(file_priorities_default_deprecated) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "", "", true).file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -288,7 +288,7 @@ TORRENT_TEST(file_priorities_default_deprecated) TORRENT_TEST(file_priorities_resume_seed_mode_deprecated) { // in share mode file priorities should always be 0 - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_share_mode, "", "123", true).file_priorities(); @@ -301,7 +301,7 @@ TORRENT_TEST(file_priorities_resume_seed_mode_deprecated) TORRENT_TEST(file_priorities_seed_mode_deprecated) { // in share mode file priorities should always be 0 - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_share_mode, "123", "", true).file_priorities(); @@ -313,8 +313,7 @@ TORRENT_TEST(file_priorities_seed_mode_deprecated) TORRENT_TEST(resume_save_load_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "123", "", true); h.save_resume_data(); @@ -340,8 +339,7 @@ TORRENT_TEST(resume_save_load_deprecated) TORRENT_TEST(resume_save_load_resume_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "", "123", true); h.save_resume_data(); @@ -370,8 +368,7 @@ TORRENT_TEST(file_priorities_resume_override_deprecated) // make sure that an empty file_priorities vector in add_torrent_params won't // override the resume data file priorities, even when override resume data // flag is set. - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_override_resume_data, "", "123", true).file_priorities(); @@ -383,8 +380,7 @@ TORRENT_TEST(file_priorities_resume_override_deprecated) TORRENT_TEST(file_priorities_resume_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "", "123", true).file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -395,8 +391,7 @@ TORRENT_TEST(file_priorities_resume_deprecated) TORRENT_TEST(file_priorities1_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "010", "", true).file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -409,8 +404,7 @@ TORRENT_TEST(file_priorities1_deprecated) TORRENT_TEST(file_priorities2_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "123", "", true).file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -421,8 +415,7 @@ TORRENT_TEST(file_priorities2_deprecated) TORRENT_TEST(file_priorities3_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "4321", "", true).file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -433,8 +426,7 @@ TORRENT_TEST(file_priorities3_deprecated) TORRENT_TEST(plain_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, 0, "", "", true).status(); default_tests(s); @@ -457,8 +449,7 @@ TORRENT_TEST(plain_deprecated) TORRENT_TEST(use_resume_save_path_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_use_resume_save_path, "", "", true).status(); default_tests(s); #ifdef TORRENT_WINDOWS @@ -480,8 +471,7 @@ TORRENT_TEST(use_resume_save_path_deprecated) TORRENT_TEST(override_resume_data_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_override_resume_data | add_torrent_params::flag_paused, "", "", true).status(); @@ -506,8 +496,7 @@ TORRENT_TEST(override_resume_data_deprecated) TORRENT_TEST(seed_mode_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_override_resume_data | add_torrent_params::flag_seed_mode, "", "", true).status(); default_tests(s); @@ -530,8 +519,7 @@ TORRENT_TEST(seed_mode_deprecated) TORRENT_TEST(upload_mode_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_upload_mode, "", "", true).status(); default_tests(s); #ifdef TORRENT_WINDOWS @@ -553,8 +541,7 @@ TORRENT_TEST(upload_mode_deprecated) TORRENT_TEST(share_mode_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_override_resume_data | add_torrent_params::flag_share_mode, "", "", true).status(); @@ -578,8 +565,7 @@ TORRENT_TEST(share_mode_deprecated) TORRENT_TEST(auto_managed_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); // resume data overrides the auto-managed flag torrent_status s = test_resume_flags(ses, add_torrent_params::flag_auto_managed, "", "", true).status(); default_tests(s); @@ -602,8 +588,7 @@ TORRENT_TEST(auto_managed_deprecated) TORRENT_TEST(paused_deprecated) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); // resume data overrides the paused flag torrent_status s = test_resume_flags(ses, add_torrent_params::flag_paused, "", "", true).status(); default_tests(s); @@ -632,8 +617,7 @@ TORRENT_TEST(url_seed_resume_data_deprecated) { // merge url seeds with resume data std::fprintf(stderr, "flags: merge_resume_http_seeds\n"); - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, add_torrent_params::flag_merge_resume_http_seeds, "", "", true); std::set us = h.url_seeds(); @@ -656,8 +640,7 @@ TORRENT_TEST(resume_override_torrent_deprecated) { // resume data overrides the .torrent_file std::fprintf(stderr, "flags: no merge_resume_http_seed\n"); - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, add_torrent_params::flag_merge_resume_trackers, "", "", true); std::set us = h.url_seeds(); @@ -675,7 +658,7 @@ TORRENT_TEST(resume_override_torrent_deprecated) TORRENT_TEST(file_priorities_default) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "", "").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -687,7 +670,7 @@ TORRENT_TEST(file_priorities_default) TORRENT_TEST(file_priorities_resume_seed_mode) { // in share mode file priorities should always be 0 - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_share_mode, "", "123").file_priorities(); @@ -700,7 +683,7 @@ TORRENT_TEST(file_priorities_resume_seed_mode) TORRENT_TEST(file_priorities_seed_mode) { // in share mode file priorities should always be 0 - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_share_mode, "123", "").file_priorities(); @@ -714,7 +697,7 @@ void test_zero_file_prio(bool test_deprecated = false) { std::fprintf(stderr, "test_file_prio\n"); - lt::session ses; + lt::session ses(settings()); std::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -781,8 +764,7 @@ void test_seed_mode(bool const file_prio, bool const pieces_have, bool const pie std::fprintf(stderr, "test_seed_mode file_prio: %d pieces_have: %d piece_prio: %d\n" , file_prio, pieces_have, piece_prio); - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -899,8 +881,7 @@ TORRENT_TEST(seed_mode_preserve) TORRENT_TEST(resume_save_load) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "123", ""); h.save_resume_data(); @@ -926,8 +907,7 @@ TORRENT_TEST(resume_save_load) TORRENT_TEST(resume_save_load_resume) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "", "123"); h.save_resume_data(); @@ -955,8 +935,7 @@ TORRENT_TEST(resume_save_load_resume) TORRENT_TEST(file_priorities_resume) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "", "123").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -967,8 +946,7 @@ TORRENT_TEST(file_priorities_resume) TORRENT_TEST(file_priorities1) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "010").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -981,8 +959,7 @@ TORRENT_TEST(file_priorities1) TORRENT_TEST(file_priorities2) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "123").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -993,8 +970,7 @@ TORRENT_TEST(file_priorities2) TORRENT_TEST(file_priorities3) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "4321").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -1005,8 +981,7 @@ TORRENT_TEST(file_priorities3) TORRENT_TEST(plain) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, 0).status(); default_tests(s); @@ -1029,8 +1004,7 @@ TORRENT_TEST(plain) TORRENT_TEST(seed_mode) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_seed_mode).status(); default_tests(s); @@ -1053,8 +1027,7 @@ TORRENT_TEST(seed_mode) TORRENT_TEST(upload_mode) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_upload_mode).status(); default_tests(s); #ifdef TORRENT_WINDOWS @@ -1076,8 +1049,7 @@ TORRENT_TEST(upload_mode) TORRENT_TEST(share_mode) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_share_mode).status(); default_tests(s); @@ -1100,8 +1072,7 @@ TORRENT_TEST(share_mode) TORRENT_TEST(auto_managed) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); // resume data overrides the auto-managed flag torrent_status s = test_resume_flags(ses, add_torrent_params::flag_auto_managed).status(); default_tests(s); @@ -1124,8 +1095,7 @@ TORRENT_TEST(auto_managed) TORRENT_TEST(paused) { - settings_pack sett = settings(); - lt::session ses(sett); + lt::session ses(settings()); // resume data overrides the paused flag torrent_status s = test_resume_flags(ses, add_torrent_params::flag_paused).status(); default_tests(s); diff --git a/test/test_session.cpp b/test/test_session.cpp index 4c31628b8..5f219c594 100644 --- a/test/test_session.cpp +++ b/test/test_session.cpp @@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bdecode.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/torrent_info.hpp" +#include "settings.hpp" #include @@ -50,11 +51,11 @@ namespace lt = libtorrent; TORRENT_TEST(session) { - settings_pack p; + settings_pack p = settings(); p.set_int(settings_pack::alert_mask, ~0); lt::session ses(p); - settings_pack sett; + settings_pack sett = settings(); sett.set_int(settings_pack::cache_size, 100); sett.set_int(settings_pack::max_queued_disk_bytes, 1000 * 16 * 1024); @@ -98,7 +99,7 @@ TORRENT_TEST(session) TORRENT_TEST(async_add_torrent_duplicate_error) { - settings_pack p; + settings_pack p = settings(); p.set_int(settings_pack::alert_mask, ~0); lt::session ses(p); @@ -122,7 +123,7 @@ TORRENT_TEST(async_add_torrent_duplicate_error) TORRENT_TEST(async_add_torrent_duplicate) { - settings_pack p; + settings_pack p = settings(); p.set_int(settings_pack::alert_mask, ~0); lt::session ses(p); @@ -148,7 +149,7 @@ TORRENT_TEST(async_add_torrent_duplicate) TORRENT_TEST(load_empty_file) { - settings_pack p; + settings_pack p = settings(); p.set_int(settings_pack::alert_mask, ~0); lt::session ses(p); @@ -180,7 +181,7 @@ TORRENT_TEST(session_stats) TORRENT_TEST(paused_session) { - lt::session s; + lt::session s(settings()); s.pause(); lt::add_torrent_params ps; @@ -203,14 +204,14 @@ void test_save_restore(Set setup, Save s, Default d, Load l) { entry st; { - settings_pack p; + settings_pack p = settings(); setup(p); lt::session ses(p); s(ses, st); } { - settings_pack p; + settings_pack p = settings(); d(p); lt::session ses(p); // the loading function takes a bdecode_node, so we have to transform the diff --git a/test/test_session_params.cpp b/test/test_session_params.cpp index c8e8a6807..1572df0f4 100644 --- a/test/test_session_params.cpp +++ b/test/test_session_params.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/session.hpp" #include "libtorrent/extensions.hpp" +#include "settings.hpp" #include "test.hpp" @@ -85,11 +86,12 @@ TORRENT_TEST(default_plugins) TORRENT_TEST(custom_dht_storage) { g_storage_constructor_invoked = false; - session_params params; + settings_pack p = settings(); + p.set_bool(settings_pack::enable_dht, true); + session_params params(p); params.dht_storage_constructor = dht_custom_storage_constructor; lt::session ses(params); - TEST_CHECK(ses.is_dht_running() == true); TEST_EQUAL(g_storage_constructor_invoked, true); } @@ -99,7 +101,7 @@ TORRENT_TEST(custom_dht_storage) TORRENT_TEST(add_plugin) { g_plugin_added_invoked = false; - session_params params; + session_params params(settings()); params.extensions.push_back(std::make_shared()); lt::session ses(params); diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index fd3945021..2be1228dc 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/extensions.hpp" +#include "settings.hpp" #include #include @@ -50,7 +51,7 @@ namespace lt = libtorrent; void test_running_torrent(std::shared_ptr info, std::int64_t file_size) { - settings_pack pack; + settings_pack pack = settings(); pack.set_int(settings_pack::alert_mask, alert::storage_notification); pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48130"); pack.set_int(settings_pack::max_retry_port_bind, 10); @@ -187,7 +188,7 @@ TORRENT_TEST(total_wanted) auto info = std::make_shared( &tmp[0], int(tmp.size()), std::ref(ec)); - settings_pack pack; + settings_pack pack = settings(); pack.set_int(settings_pack::alert_mask, alert::storage_notification); pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48130"); pack.set_int(settings_pack::max_retry_port_bind, 10); @@ -225,7 +226,7 @@ TORRENT_TEST(added_peers) auto info = std::make_shared( &tmp[0], int(tmp.size()), std::ref(ec)); - settings_pack pack; + settings_pack pack = settings(); pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48130"); pack.set_int(settings_pack::max_retry_port_bind, 10); lt::session ses(pack); @@ -354,7 +355,7 @@ TORRENT_TEST(duplicate_is_not_error) p.save_path = "."; p.extensions.push_back(creator); - lt::session ses; + lt::session ses(settings()); ses.async_add_torrent(p); ses.async_add_torrent(p); diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 2b0ac7290..e921963d7 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -128,6 +128,8 @@ static test_torrent_t test_torrents[] = { "invalid_name3.torrent" }, { "symlink1.torrent" }, { "unordered.torrent" }, + { "symlink_zero_size.torrent" }, + { "pad_file_no_path.torrent" }, }; struct test_failing_torrent_t @@ -147,13 +149,14 @@ test_failing_torrent_t test_error_torrents[] = { "string.torrent", errors::torrent_is_no_dict }, { "negative_size.torrent", errors::torrent_invalid_length }, { "negative_file_size.torrent", errors::torrent_invalid_length }, - { "invalid_path_list.torrent", errors::torrent_missing_name}, + { "invalid_path_list.torrent", errors::torrent_invalid_name}, { "missing_path_list.torrent", errors::torrent_missing_name }, { "invalid_pieces.torrent", errors::torrent_missing_pieces }, { "unaligned_pieces.torrent", errors::torrent_invalid_hashes }, { "invalid_root_hash.torrent", errors::torrent_invalid_hashes }, { "invalid_root_hash2.torrent", errors::torrent_missing_pieces }, { "invalid_file_size.torrent", errors::torrent_invalid_length }, + { "invalid_symlink.torrent", errors::torrent_invalid_name }, }; // TODO: test remap_files @@ -164,7 +167,6 @@ test_failing_torrent_t test_error_torrents[] = // TODO: torrent with 'l' (symlink) attribute // TODO: creating a merkle torrent (torrent_info::build_merkle_list) // TODO: torrent with multiple trackers in multiple tiers, making sure we shuffle them (how do you test shuffling?, load it multiple times and make sure it's in different order at least once) -// TODO: torrents with a missing name // TODO: torrents with a zero-length name // TODO: torrents with a merkle tree and add_merkle_nodes // TODO: torrent with a non-dictionary info-section @@ -714,6 +716,16 @@ TORRENT_TEST(parse_torrents) TEST_EQUAL(ti->num_files(), 1); TEST_EQUAL(ti->files().file_path(0), "temp....abc"); } + else if (std::string(test_torrents[i].file) == "symlink_zero_size.torrent") + { + TEST_EQUAL(ti->num_files(), 2); + TEST_EQUAL(ti->files().symlink(1), combine_path("foo", "bar")); + } + else if (std::string(test_torrents[i].file) == "pad_file_no_path.torrent") + { + TEST_EQUAL(ti->num_files(), 2); + TEST_EQUAL(ti->files().file_path(1), combine_path(".pad", "0")); + } file_storage const& fs = ti->files(); for (int i = 0; i < fs.num_files(); ++i) diff --git a/test/test_torrents/invalid_symlink.torrent b/test/test_torrents/invalid_symlink.torrent new file mode 100644 index 000000000..8ef6c72fa --- /dev/null +++ b/test/test_torrents/invalid_symlink.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi0e4:pathl1:a1:b3:bareed4:attr1:l6:lengthi425e4:pathl1:a1:b3:foo12:symlink pathl3:foo3:bari4eeeee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee diff --git a/test/test_torrents/pad_file_no_path.torrent b/test/test_torrents/pad_file_no_path.torrent new file mode 100644 index 000000000..d878b2c41 --- /dev/null +++ b/test/test_torrents/pad_file_no_path.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld4:pathl3:foo7:bar.txte6:lengthi45eed4:attr1:p6:lengthi2124eee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee diff --git a/test/test_torrents/symlink1.torrent b/test/test_torrents/symlink1.torrent index 3c3ddc3b0..e41e6c2d9 100644 --- a/test/test_torrents/symlink1.torrent +++ b/test/test_torrents/symlink1.torrent @@ -1 +1 @@ -d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl1:a1:b3:bareed4:attr1:l6:lengthi425e4:pathl1:a1:b3:fooeee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl1:a1:b3:bareed4:attr1:l6:lengthi425e4:pathl1:a1:b3:fooe12:symlink pathl3:foo3:bareee4:name4:temp12:piece lengthi16384e6:pieces20:‚ž¼Œ&¾ÇJW›}ÜA4u,·¼‘‡ee diff --git a/test/test_torrents/symlink_zero_size.torrent b/test/test_torrents/symlink_zero_size.torrent new file mode 100644 index 000000000..a7f225a0d --- /dev/null +++ b/test/test_torrents/symlink_zero_size.torrent @@ -0,0 +1 @@ +d10:created by10:libtorrent13:creation datei1359599503e4:infod5:filesld6:lengthi425e4:pathl1:a1:b3:bareed4:attr1:l4:pathl1:a1:b3:fooe12:symlink pathl3:foo3:bareee4:name4:temp12:piece lengthi16384e6:pieces20:aaaaaaaaaaaaaaaaaaaaee diff --git a/test/test_web_seed_redirect.cpp b/test/test_web_seed_redirect.cpp index bcfb79a5b..22f03a2f2 100644 --- a/test/test_web_seed_redirect.cpp +++ b/test/test_web_seed_redirect.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" #include "web_seed_suite.hpp" +#include "settings.hpp" #include "libtorrent/create_torrent.hpp" #include "libtorrent/torrent_info.hpp" @@ -88,10 +89,10 @@ TORRENT_TEST(web_seed_redirect) , int(buf.size()), ec); { - settings_pack settings; - settings.set_int(settings_pack::max_queued_disk_bytes, 256 * 1024); - settings.set_int(settings_pack::alert_mask, ~(alert::progress_notification | alert::stats_notification)); - libtorrent::session ses(settings); + settings_pack p = settings(); + p.set_int(settings_pack::max_queued_disk_bytes, 256 * 1024); + p.set_int(settings_pack::alert_mask, ~(alert::progress_notification | alert::stats_notification)); + libtorrent::session ses(p); // disable keep-alive because otherwise the test will choke on seeing // the disconnect (from the redirect)