From 8007b947fd313bba2045374c76714cf76677e13b Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 7 Aug 2016 22:37:10 -0400 Subject: [PATCH 1/8] make pad-file and symlink support conform to BEP47 (#992) make pad-file and symlink support conform to BEP47 --- ChangeLog | 1 + include/libtorrent/bdecode.hpp | 2 +- src/create_torrent.cpp | 2 +- src/file_storage.cpp | 31 ++-- src/torrent_info.cpp | 154 ++++++++++++------- test/Makefile.am | 3 + test/test_torrent_info.cpp | 16 +- test/test_torrents/invalid_symlink.torrent | 1 + test/test_torrents/pad_file_no_path.torrent | 1 + test/test_torrents/symlink1.torrent | 2 +- test/test_torrents/symlink_zero_size.torrent | 1 + 11 files changed, 140 insertions(+), 74 deletions(-) create mode 100644 test/test_torrents/invalid_symlink.torrent create mode 100644 test/test_torrents/pad_file_no_path.torrent create mode 100644 test/test_torrents/symlink_zero_size.torrent diff --git a/ChangeLog b/ChangeLog index f23781709..868803c64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 1.1.1 release + * 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/include/libtorrent/bdecode.hpp b/include/libtorrent/bdecode.hpp index 34dea075a..d95a59d5c 100644 --- a/include/libtorrent/bdecode.hpp +++ b/include/libtorrent/bdecode.hpp @@ -109,7 +109,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/src/create_torrent.cpp b/src/create_torrent.cpp index 8343054dd..dda3d4712 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -548,7 +548,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 41fde9ac6..834a075f1 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 namespace libtorrent @@ -538,10 +540,10 @@ namespace libtorrent , symlink_path); } - void file_storage::add_file_borrow(char const* filename, int filename_len - , std::string const& path, boost::int64_t file_size - , boost::uint32_t file_flags, char const* filehash - , boost::int64_t mtime, std::string const& symlink_path) + void file_storage::add_file_borrow(char const* filename, int const filename_len + , std::string const& path, boost::int64_t const file_size + , boost::uint32_t const file_flags, char const* filehash + , boost::int64_t const mtime, std::string const& symlink_path) { TORRENT_ASSERT_PRECOND(file_size >= 0); if (!has_parent_path(path)) @@ -576,10 +578,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) { @@ -611,7 +613,7 @@ namespace libtorrent if (index >= int(m_file_hashes.size())) return sha1_hash(0); return sha1_hash(m_file_hashes[index]); } - + std::string const& file_storage::symlink(int index) const { TORRENT_ASSERT_PRECOND(index >= 0 && index < int(m_files.size())); @@ -965,8 +967,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; } @@ -979,8 +981,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(); @@ -1064,7 +1066,8 @@ namespace libtorrent e.size = size; e.offset = offset; char name[30]; - snprintf(name, sizeof(name), ".____padding_file/%d", pad_file_counter); + 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/torrent_info.cpp b/src/torrent_info.cpp index 14034b1b5..140d7611b 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -161,7 +161,8 @@ namespace libtorrent return valid_encoding; } - void sanitize_append_path_element(std::string& path, char const* element, int element_len) + void sanitize_append_path_element(std::string& path + , char const* element, int element_len) { if (element_len == 1 && element[0] == '.') return; @@ -390,6 +391,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" @@ -397,17 +438,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; - boost::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; } - boost::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; @@ -434,71 +482,63 @@ 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_ptr(), e.string_length()); + } + } + 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 = 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_ptr(), e.string_length()); - } } // bitcomet pad file - boost::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 = NULL; 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")) { - std::string pe = s_p.list_at(i).string_value(); - symlink_path = combine_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) + { + bdecode_node const& n = s_p.list_at(i); + sanitize_append_path_element(symlink_path, n.string_ptr() + , n.string_length()); + } } } else @@ -591,10 +631,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; @@ -1226,7 +1268,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_multifile = false; @@ -1287,7 +1331,7 @@ namespace libtorrent m_merkle_tree[0].assign(root_hash.string_ptr()); } - m_private = info.dict_find_int_value("private", 0); + m_private = info.dict_find_int_value("private", 0) != 0; #ifndef TORRENT_DISABLE_MUTABLE_TORRENTS bdecode_node similar = info.dict_find_list("similar"); diff --git a/test/Makefile.am b/test/Makefile.am index cb25fc037..40577945f 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 \ diff --git a/test/test_torrent_info.cpp b/test/test_torrent_info.cpp index 87b092dc6..1e35d82ce 100644 --- a/test/test_torrent_info.cpp +++ b/test/test_torrent_info.cpp @@ -132,6 +132,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 @@ -151,13 +153,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 @@ -168,7 +171,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 @@ -718,6 +720,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 From 1229491e5e9cd5df4fc7c2b7664a2983392bc3c8 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Wed, 10 Aug 2016 07:26:02 -0400 Subject: [PATCH 2/8] back-port python3 fix --- bindings/python/src/entry.cpp | 4 ++-- bindings/python/test.py | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/bindings/python/src/entry.cpp b/bindings/python/src/entry.cpp index 5019920f1..db43b5b1b 100644 --- a/bindings/python/src/entry.cpp +++ b/bindings/python/src/entry.cpp @@ -51,7 +51,7 @@ struct entry_to_python list l; for (std::vector::const_iterator i = pre.begin() , end(pre.end()); i != end; ++i) - l.append(*i); + l.append(int(*i)); return tuple(l); } default: @@ -153,7 +153,7 @@ struct entry_from_python std::vector preformatted(length); for (std::size_t i = 0; i < length; ++i) { - preformatted[i] = extract(t[i]); + preformatted[i] = char(extract(t[i])); } return entry(preformatted); diff --git a/bindings/python/test.py b/bindings/python/test.py index d46e5b0ab..538a01b8a 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -16,10 +16,11 @@ class test_create_torrent(unittest.TestCase): ct = lt.create_torrent(ti) entry = ct.generate() content = lt.bencode(entry).strip() - with open('unordered.torrent', 'r') as f: - file_content = f.read().strip() - print file_content - print content + with open('unordered.torrent', 'rb') as f: + file_content = bytearray(f.read().strip()) + print(content) + print(file_content) + print(entry) self.assertEqual(content, file_content) class test_torrent_handle(unittest.TestCase): From e247473b86b3c21f89b2e4f4baa0f87a93f92ed6 Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 13 Aug 2016 07:12:23 -0400 Subject: [PATCH 3/8] bump version number --- CMakeLists.txt | 2 +- Jamfile | 2 +- bindings/python/setup.py | 2 +- configure.ac | 2 +- docs/building.rst | 2 +- docs/contributing.rst | 2 +- docs/dht_rss.rst | 2 +- docs/dht_sec.rst | 2 +- docs/dht_store.rst | 2 +- docs/examples.rst | 2 +- docs/features.rst | 2 +- docs/gen_reference_doc.py | 2 +- docs/hacking.rst | 2 +- docs/index.rst | 2 +- docs/manual.rst | 2 +- docs/troubleshooting.rst | 2 +- docs/tuning.rst | 2 +- docs/tutorial.rst | 2 +- docs/utp.rst | 2 +- include/libtorrent/version.hpp | 6 +++--- src/settings_pack.cpp | 2 +- 21 files changed, 23 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d0846d1e7..37c2ad28e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.6) project(libtorrent) set (SOVERSION "8") -set (VERSION "1.1.0") +set (VERSION "1.1.1") set(sources web_connection_base diff --git a/Jamfile b/Jamfile index ba51a7be5..ddae14729 100644 --- a/Jamfile +++ b/Jamfile @@ -58,7 +58,7 @@ else : : $(boost-include-path) ; } -VERSION = 1.1.0 ; +VERSION = 1.1.1 ; # rule for linking the correct libraries depending # on features and target-os diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 13b25e84a..69de9b95b 100644 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -126,7 +126,7 @@ else: libraries = ['torrent-rasterbar'] + flags.libraries)] setup(name = 'python-libtorrent', - version = '1.1.0', + version = '1.1.1', author = 'Arvid Norberg', author_email = 'arvid@libtorrent.org', description = 'Python bindings for libtorrent-rasterbar', diff --git a/configure.ac b/configure.ac index c085f9def..6ccc15ab4 100644 --- a/configure.ac +++ b/configure.ac @@ -5,7 +5,7 @@ AC_PREREQ([2.63]) -AC_INIT([libtorrent-rasterbar],[1.1.0],[arvid@libtorrent.org], +AC_INIT([libtorrent-rasterbar],[1.1.1],[arvid@libtorrent.org], [libtorrent-rasterbar],[http://www.libtorrent.org]) AC_CONFIG_SRCDIR([src/torrent.cpp]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/docs/building.rst b/docs/building.rst index 42c5c8939..9476448d6 100644 --- a/docs/building.rst +++ b/docs/building.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/contributing.rst b/docs/contributing.rst index 35307c9e2..00a7a988b 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/dht_rss.rst b/docs/dht_rss.rst index a49876a56..c3dcc32e1 100644 --- a/docs/dht_rss.rst +++ b/docs/dht_rss.rst @@ -3,7 +3,7 @@ BitTorrent extension for DHT RSS feeds ====================================== :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/dht_sec.rst b/docs/dht_sec.rst index 77fb7a010..67fea182f 100644 --- a/docs/dht_sec.rst +++ b/docs/dht_sec.rst @@ -3,7 +3,7 @@ BitTorrent DHT security extension ================================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/dht_store.rst b/docs/dht_store.rst index 5605a459a..86a5c90a5 100644 --- a/docs/dht_store.rst +++ b/docs/dht_store.rst @@ -3,7 +3,7 @@ BitTorrent extension for arbitrary DHT store ============================================ :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/examples.rst b/docs/examples.rst index 9e153611a..21a171495 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -3,7 +3,7 @@ libtorrent Examples =================== :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/features.rst b/docs/features.rst index a16d5a1b8..7f2cc4f06 100644 --- a/docs/features.rst +++ b/docs/features.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/gen_reference_doc.py b/docs/gen_reference_doc.py index 0bc999306..841dfd1e6 100644 --- a/docs/gen_reference_doc.py +++ b/docs/gen_reference_doc.py @@ -1003,7 +1003,7 @@ for cat in categories: out.write(''' :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 %s diff --git a/docs/hacking.rst b/docs/hacking.rst index a3e414189..d4a5b4078 100644 --- a/docs/hacking.rst +++ b/docs/hacking.rst @@ -3,7 +3,7 @@ libtorrent hacking ================== :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/index.rst b/docs/index.rst index cb816b59d..cb033c694 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,5 @@ :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. raw:: html diff --git a/docs/manual.rst b/docs/manual.rst index c78062485..13066d5a7 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3,7 +3,7 @@ libtorrent API Documentation ============================ :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 1 diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 3166e5994..b058e8015 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/tuning.rst b/docs/tuning.rst index 96c8cd164..b1dcf192a 100644 --- a/docs/tuning.rst +++ b/docs/tuning.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/tutorial.rst b/docs/tutorial.rst index eae609ac7..47cd26783 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/docs/utp.rst b/docs/utp.rst index e8709b6c1..f92dd2e4e 100644 --- a/docs/utp.rst +++ b/docs/utp.rst @@ -3,7 +3,7 @@ libtorrent manual ================= :Author: Arvid Norberg, arvid@libtorrent.org -:Version: 1.1.0 +:Version: 1.1.1 .. contents:: Table of contents :depth: 2 diff --git a/include/libtorrent/version.hpp b/include/libtorrent/version.hpp index 3dafe18e1..75f8d5300 100644 --- a/include/libtorrent/version.hpp +++ b/include/libtorrent/version.hpp @@ -37,14 +37,14 @@ POSSIBILITY OF SUCH DAMAGE. #define LIBTORRENT_VERSION_MAJOR 1 #define LIBTORRENT_VERSION_MINOR 1 -#define LIBTORRENT_VERSION_TINY 0 +#define LIBTORRENT_VERSION_TINY 1 // the format of this version is: MMmmtt // M = Major version, m = minor version, t = tiny version #define LIBTORRENT_VERSION_NUM ((LIBTORRENT_VERSION_MAJOR * 10000) + (LIBTORRENT_VERSION_MINOR * 100) + LIBTORRENT_VERSION_TINY) -#define LIBTORRENT_VERSION "1.1.0.0" -#define LIBTORRENT_REVISION "044ee0f" +#define LIBTORRENT_VERSION "1.1.1.0" +#define LIBTORRENT_REVISION "1229491" namespace libtorrent { diff --git a/src/settings_pack.cpp b/src/settings_pack.cpp index 067c8acc0..1c2f2e8a9 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -137,7 +137,7 @@ 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, "-LT1100-", &session_impl::update_peer_fingerprint) + SET_NOPREV(peer_fingerprint, "-LT1110-", &session_impl::update_peer_fingerprint) }; bool_setting_entry_t bool_settings[settings_pack::num_bool_settings] = From b701fb252aa166314b13663ab2be29e181668b46 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 20 Aug 2016 11:04:44 -0400 Subject: [PATCH 4/8] clear alert nofify function when calling abort on a session, to avoid touching a destructed session object (#1015) --- include/libtorrent/session.hpp | 2 +- simulation/test_checking.cpp | 1 - simulation/test_fast_extensions.cpp | 1 - simulation/test_ip_filter.cpp | 1 - simulation/test_optimistic_unchoke.cpp | 1 - simulation/test_socks5.cpp | 1 - simulation/test_tracker.cpp | 2 -- simulation/test_transfer.cpp | 1 - simulation/test_web_seed.cpp | 1 - src/session.cpp | 8 ++++++++ src/session_impl.cpp | 4 ++++ 11 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 7f0f85264..f16f41e15 100644 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -281,7 +281,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/simulation/test_checking.cpp b/simulation/test_checking.cpp index 9fd3e044d..9754b174e 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_fast_extensions.cpp b/simulation/test_fast_extensions.cpp index ae3350e22..3c50126d0 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& ec) { - ses->set_alert_notify([]{}); // shut down zombie = ses->abort(); diff --git a/simulation/test_ip_filter.cpp b/simulation/test_ip_filter.cpp index 576dcb7d7..becadefe1 100644 --- a/simulation/test_ip_filter.cpp +++ b/simulation/test_ip_filter.cpp @@ -88,7 +88,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 f6ff2dc00..78e560959 100644 --- a/simulation/test_optimistic_unchoke.cpp +++ b/simulation/test_optimistic_unchoke.cpp @@ -148,7 +148,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 b0d78834c..f4940ec4a 100644 --- a/simulation/test_socks5.cpp +++ b/simulation/test_socks5.cpp @@ -101,7 +101,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/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 64ae26d4f..e5abcee0f 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -352,7 +352,6 @@ TORRENT_TEST(ipv6_support) , [&ses,&zombie](boost::system::error_code const& ec) { zombie = ses->abort(); - ses->set_alert_notify([]{}); ses.reset(); }); @@ -427,7 +426,6 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 , [&ses,&zombie](boost::system::error_code const& ec) { zombie = ses->abort(); - ses->set_alert_notify([]{}); ses.reset(); }); diff --git a/simulation/test_transfer.cpp b/simulation/test_transfer.cpp index ddc3aceaf..5b732e170 100644 --- a/simulation/test_transfer.cpp +++ b/simulation/test_transfer.cpp @@ -139,7 +139,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 1468f7db6..da99e5dc8 100644 --- a/simulation/test_web_seed.cpp +++ b/simulation/test_web_seed.cpp @@ -113,7 +113,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/session.cpp b/src/session.cpp index a0bac8e5f..125f4f310 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -409,6 +409,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(boost::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 33f0ddc6d..c27a551c2 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1076,6 +1076,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(boost::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 From daa453ef3b5ff62b51a73e8ba0263887b0a94e3b Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 21 Aug 2016 01:07:02 -0400 Subject: [PATCH 5/8] back-port windows stack trace function to 1.1 (#1017) back port exception handling and stack trace printing from master -> RC_1_1 --- include/libtorrent/assert.hpp | 3 +- src/assert.cpp | 148 ++++++++++++++++++++++------------ test/main.cpp | 93 ++++++++++++++++----- 3 files changed, 171 insertions(+), 73 deletions(-) diff --git a/include/libtorrent/assert.hpp b/include/libtorrent/assert.hpp index ac1bcda8a..d8dee26d8 100644 --- a/include/libtorrent/assert.hpp +++ b/include/libtorrent/assert.hpp @@ -42,7 +42,8 @@ POSSIBILITY OF SUCH DAMAGE. #include std::string demangle(char const* name); -TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth = 0); +TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth = 0 + , void* ctx = NULL); #endif // this is to disable the warning of conditional expressions diff --git a/src/assert.cpp b/src/assert.cpp index f05965fc8..5b54dd353 100644 --- a/src/assert.cpp +++ b/src/assert.cpp @@ -39,10 +39,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #endif -#if (defined TORRENT_DEBUG && TORRENT_USE_ASSERTS) \ +#if TORRENT_USE_ASSERTS \ || defined TORRENT_ASIO_DEBUGGING \ || defined TORRENT_PROFILE_CALLS \ - || defined TORRENT_RELEASE_ASSERTS \ || defined TORRENT_DEBUG_BUFFERS #ifdef __APPLE__ @@ -51,8 +50,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include -#include +#include +#include +#include // for snprintf +#include #include "libtorrent/aux_/disable_warnings_pop.hpp" @@ -67,7 +68,7 @@ std::string demangle(char const* name) // in case this string comes // this is needed on linux char const* start = strchr(name, '('); - if (start != 0) + if (start != NULL) { ++start; } @@ -75,10 +76,10 @@ std::string demangle(char const* name) { // this is needed on macos x start = strstr(name, "0x"); - if (start != 0) + if (start != NULL) { start = strchr(start, ' '); - if (start != 0) ++start; + if (start != NULL) ++start; else start = name; } else start = name; @@ -88,13 +89,13 @@ std::string demangle(char const* name) if (end) while (*(end-1) == ' ') --end; std::string in; - if (end == 0) in.assign(start); + if (end == NULL) in.assign(start); else in.assign(start, end); size_t len; int status; - char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status); - if (unmangled == 0) return in; + char* unmangled = ::abi::__cxa_demangle(in.c_str(), NULL, &len, &status); + if (unmangled == NULL) return in; std::string ret(unmangled); free(unmangled); return ret; @@ -116,15 +117,15 @@ std::string demangle(char const* name) std::string demangle(char const* name) { return name; } #endif -#include -#include -#include +#include +#include +#include #include "libtorrent/version.hpp" #if TORRENT_USE_EXECINFO #include -TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) +TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth, void*) { void* stack[50]; int size = backtrace(stack, 50); @@ -141,8 +142,7 @@ TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) free(symbols); } -// visual studio 9 and up appears to support this -#elif defined _WIN32 && _MSC_VER >= 1500 +#elif defined _WIN32 #include "windows.h" #include "libtorrent/utf8.hpp" @@ -151,41 +151,61 @@ TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) #include "winbase.h" #include "dbghelp.h" -static libtorrent::mutex dbghlp_mutex; - -TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) +TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth + , void* ctx) { // all calls to DbgHlp.dll are thread-unsafe. i.e. they all need to be // synchronized and not called concurrently. This mutex serializes access + static libtorrent::mutex dbghlp_mutex; libtorrent::mutex::scoped_lock l(dbghlp_mutex); - typedef USHORT (WINAPI *RtlCaptureStackBackTrace_t)( - __in ULONG FramesToSkip, - __in ULONG FramesToCapture, - __out PVOID *BackTrace, - __out_opt PULONG BackTraceHash); - - static RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace = 0; - - if (RtlCaptureStackBackTrace == 0) + CONTEXT context_record; + if (ctx) { - // we don't actually have to free this library, everyone has it loaded - HMODULE lib = LoadLibrary(TEXT("kernel32.dll")); - RtlCaptureStackBackTrace = (RtlCaptureStackBackTrace_t)GetProcAddress(lib, "RtlCaptureStackBackTrace"); - if (RtlCaptureStackBackTrace == 0) - { - out[0] = 0; - return; - } + context_record = *static_cast(ctx); + } + else + { + // use the current thread's context + RtlCaptureContext(&context_record); } - int i; - void* stack[50]; - int size = CaptureStackBackTrace(0, 50, stack, 0); + int size = 0; + boost::array stack; - SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR), 1); - symbol->MaxNameLen = MAX_SYM_NAME; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + STACKFRAME64 stack_frame; + memset(&stack_frame, 0, sizeof(stack_frame)); +#if defined(_WIN64) + int const machine_type = IMAGE_FILE_MACHINE_AMD64; + stack_frame.AddrPC.Offset = context_record.Rip; + stack_frame.AddrFrame.Offset = context_record.Rbp; + stack_frame.AddrStack.Offset = context_record.Rsp; +#else + int const machine_type = IMAGE_FILE_MACHINE_I386; + stack_frame.AddrPC.Offset = context_record.Eip; + stack_frame.AddrFrame.Offset = context_record.Ebp; + stack_frame.AddrStack.Offset = context_record.Esp; +#endif + stack_frame.AddrPC.Mode = AddrModeFlat; + stack_frame.AddrFrame.Mode = AddrModeFlat; + stack_frame.AddrStack.Mode = AddrModeFlat; + while (StackWalk64(machine_type, + GetCurrentProcess(), + GetCurrentThread(), + &stack_frame, + &context_record, + NULL, + &SymFunctionTableAccess64, + &SymGetModuleBase64, + NULL) && size < stack.size()) + { + stack[size++] = reinterpret_cast(stack_frame.AddrPC.Offset); + } + + struct symbol_bundle : SYMBOL_INFO + { + wchar_t name[MAX_SYM_NAME]; + }; HANDLE p = GetCurrentProcess(); static bool sym_initialized = false; @@ -194,24 +214,52 @@ TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) sym_initialized = true; SymInitialize(p, NULL, true); } - for (i = 0; i < size && len > 0; ++i) + SymRefreshModuleList(p); + for (int i = 0; i < size && len > 0; ++i) { - int ret; - if (SymFromAddr(p, uintptr_t(stack[i]), 0, symbol)) - ret = snprintf(out, len, "%d: %s\n", i, symbol->Name); - else - ret = snprintf(out, len, "%d: \n", i); + DWORD_PTR frame_ptr = reinterpret_cast(stack[i]); + DWORD64 displacement = 0; + symbol_bundle symbol; + symbol.MaxNameLen = MAX_SYM_NAME; + symbol.SizeOfStruct = sizeof(SYMBOL_INFO); + BOOL const has_symbol = SymFromAddr(p, frame_ptr, &displacement, &symbol); + + DWORD line_displacement = 0; + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + BOOL const has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame_ptr, + &line_displacement, &line); + + int ret = snprintf(out, len, "%2d: %p", i, stack[i]); + out += ret; len -= ret; if (len <= 0) break; + + if (has_symbol) + { + ret = snprintf(out, len, " %s +%-4" PRId64 + , demangle(symbol.Name).c_str(), displacement); + out += ret; len -= ret; if (len <= 0) break; + } + + if (has_line) + { + ret = snprintf(out, len, " %s:%d" + , line.FileName, line.LineNumber); + out += ret; len -= ret; if (len <= 0) break; + } + + + ret = snprintf(out, len, "\n"); out += ret; len -= ret; + if (i == max_depth && max_depth > 0) break; } - free(symbol); } #else -TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth) +TORRENT_EXPORT void print_backtrace(char* out, int len, int /*max_depth*/, void* /* ctx */) { out[0] = 0; strncat(out, "", len); diff --git a/test/main.cpp b/test/main.cpp index 678774e3d..8061038e0 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -97,6 +97,62 @@ void output_test_log_to_terminal() } while (size > 0); } +#ifdef _WIN32 +LONG WINAPI seh_exception_handler(LPEXCEPTION_POINTERS p) +{ + char stack_text[10000]; + +#if TORRENT_USE_ASSERTS \ + || defined TORRENT_ASIO_DEBUGGING \ + || defined TORRENT_PROFILE_CALLS \ + || defined TORRENT_DEBUG_BUFFERS + print_backtrace(stack_text, sizeof(stack_text), 30 + , p->ContextRecord); +#elif defined __FUNCTION__ + strcat(stack_text, __FUNCTION__); +#else + stack_text[0] = 0; + strcat(stack_text, ""); +#endif + + int const code = p->ExceptionRecord->ExceptionCode; + char const* name = ""; + switch (code) + { +#define EXC(x) case x: name = #x; break + EXC(EXCEPTION_ACCESS_VIOLATION); + EXC(EXCEPTION_ARRAY_BOUNDS_EXCEEDED); + EXC(EXCEPTION_BREAKPOINT); + EXC(EXCEPTION_DATATYPE_MISALIGNMENT); + EXC(EXCEPTION_FLT_DENORMAL_OPERAND); + EXC(EXCEPTION_FLT_DIVIDE_BY_ZERO); + EXC(EXCEPTION_FLT_INEXACT_RESULT); + EXC(EXCEPTION_FLT_INVALID_OPERATION); + EXC(EXCEPTION_FLT_OVERFLOW); + EXC(EXCEPTION_FLT_STACK_CHECK); + EXC(EXCEPTION_FLT_UNDERFLOW); + EXC(EXCEPTION_ILLEGAL_INSTRUCTION); + EXC(EXCEPTION_IN_PAGE_ERROR); + EXC(EXCEPTION_INT_DIVIDE_BY_ZERO); + EXC(EXCEPTION_INT_OVERFLOW); + EXC(EXCEPTION_INVALID_DISPOSITION); + EXC(EXCEPTION_NONCONTINUABLE_EXCEPTION); + EXC(EXCEPTION_PRIV_INSTRUCTION); + EXC(EXCEPTION_SINGLE_STEP); + EXC(EXCEPTION_STACK_OVERFLOW); +#undef EXC + }; + + std::fprintf(stderr, "exception: (0x%x) %s caught:\n%s\n" + , code, name, stack_text); + + output_test_log_to_terminal(); + + exit(code); +} + +#else + void sig_handler(int sig) { char stack_text[10000]; @@ -142,6 +198,8 @@ void sig_handler(int sig) #endif } +#endif // _WIN32 + void print_usage(char const* executable) { printf("%s [options] [tests...]\n" @@ -159,17 +217,6 @@ void print_usage(char const* executable) "by -l. If no test is specified, all tests are run\n", executable); } -#ifdef WIN32 -LONG WINAPI seh_exception_handler(LPEXCEPTION_POINTERS p) -{ - int sig = p->ExceptionRecord->ExceptionCode; - fprintf(stderr, "SEH exception: %u\n" - , p->ExceptionRecord->ExceptionCode); - sig_handler(sig); - exit(sig); -} -#endif - EXPORT int main(int argc, char const* argv[]) { char const* executable = argv[0]; @@ -218,6 +265,16 @@ EXPORT int main(int argc, char const* argv[]) filter = true; } +#ifdef O_NONBLOCK + // on darwin, stdout is set to non-blocking mode by default + // which sometimes causes tests to fail with EAGAIN just + // by printing logs + int flags = fcntl(fileno(stdout), F_GETFL, 0); + fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK); + flags = fcntl(fileno(stderr), F_GETFL, 0); + fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK); +#endif + #ifdef WIN32 // try to suppress hanging the process by windows displaying // modal dialogs. @@ -231,17 +288,7 @@ EXPORT int main(int argc, char const* argv[]) _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); #endif -#endif - -#ifdef O_NONBLOCK - // on darwin, stdout is set to non-blocking mode by default - // which sometimes causes tests to fail with EAGAIN just - // by printing logs - int flags = fcntl(fileno(stdout), F_GETFL, 0); - fcntl(fileno(stdout), F_SETFL, flags & ~O_NONBLOCK); - flags = fcntl(fileno(stderr), F_GETFL, 0); - fcntl(fileno(stderr), F_SETFL, flags & ~O_NONBLOCK); -#endif +#else signal(SIGSEGV, &sig_handler); #ifdef SIGBUS @@ -255,6 +302,8 @@ EXPORT int main(int argc, char const* argv[]) signal(SIGSYS, &sig_handler); #endif +#endif // WIN32 + int process_id = -1; #ifdef _WIN32 process_id = _getpid(); From bfe9934d57a8f454ce195bb5bf7486d3d519db9d Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 21 Aug 2016 09:37:39 -0400 Subject: [PATCH 6/8] try previous build image (#1019) --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index b887e78b2..cbb8df2a6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ branches: only: - master - RC_1_1 -os: Visual Studio 2015 +os: Previous Visual Studio 2015 clone_depth: 1 environment: matrix: From 80e5ce9b32687a6e2cc980669c358482cb4316fc Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 21 Aug 2016 12:15:19 -0400 Subject: [PATCH 7/8] add a default DHT bootstrap node when it's enabled on session startup (#1008) make the dht bootstrap nodes part of settings_pack instead, to make it possible to set them on startup. and add default --- ChangeLog | 1 + bindings/python/test.py | 14 ++-- include/libtorrent/aux_/session_impl.hpp | 1 + include/libtorrent/settings_pack.hpp | 9 +++ simulation/Jamfile | 1 + simulation/fake_peer.hpp | 51 +++++++++++++ simulation/test_dht_bootstrap.cpp | 96 ++++++++++++++++++++++++ src/session_impl.cpp | 15 ++++ src/settings_pack.cpp | 3 +- src/string_util.cpp | 2 +- test/settings.cpp | 1 + test/test_dht_storage.cpp | 3 + test/test_direct_dht.cpp | 2 + test/test_ip_filter.cpp | 3 +- test/test_magnet.cpp | 7 +- test/test_priority.cpp | 7 +- test/test_privacy.cpp | 3 +- test/test_resume.cpp | 47 ++++++------ test/test_session.cpp | 13 ++-- test/test_torrent.cpp | 9 ++- test/test_web_seed_redirect.cpp | 9 ++- 21 files changed, 243 insertions(+), 54 deletions(-) create mode 100644 simulation/test_dht_bootstrap.cpp diff --git a/ChangeLog b/ChangeLog index 868803c64..6ac1549b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 1.1.1 release + * 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 diff --git a/bindings/python/test.py b/bindings/python/test.py index 538a01b8a..4e5fa9afe 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()}) @@ -66,7 +66,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() @@ -83,7 +83,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() @@ -108,7 +108,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 @@ -150,7 +150,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)) @@ -161,7 +161,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) @@ -170,7 +170,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 93e906885..6a6424dae 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -656,6 +656,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/settings_pack.hpp b/include/libtorrent/settings_pack.hpp index a62077098..6776de8c3 100644 --- a/include/libtorrent/settings_pack.hpp +++ b/include/libtorrent/settings_pack.hpp @@ -204,6 +204,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/simulation/Jamfile b/simulation/Jamfile index fb8a38ab8..2daf9b873 100644 --- a/simulation/Jamfile +++ b/simulation/Jamfile @@ -37,6 +37,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 ae34faf79..1ed6925d0 100644 --- a/simulation/fake_peer.hpp +++ b/simulation/fake_peer.hpp @@ -43,6 +43,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; @@ -184,6 +185,56 @@ private: std::vector m_send_buffer; }; +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; +}; + inline void add_fake_peers(lt::torrent_handle h) { // add the fake peers diff --git a/simulation/test_dht_bootstrap.cpp b/simulation/test_dht_bootstrap.cpp new file mode 100644 index 000000000..fe3af95cf --- /dev/null +++ b/simulation/test_dht_bootstrap.cpp @@ -0,0 +1,96 @@ +/* + +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" + +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/src/session_impl.cpp b/src/session_impl.cpp index c27a551c2..49c40fd11 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -633,6 +633,7 @@ namespace aux { update_lsd(); update_dht(); update_peer_fingerprint(); + update_dht_bootstrap_nodes(); if (m_listen_sockets.empty()) { @@ -5482,6 +5483,20 @@ retry: } } + 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 1c2f2e8a9..d45a6aaa7 100644 --- a/src/settings_pack.cpp +++ b/src/settings_pack.cpp @@ -137,7 +137,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, "-LT1110-", &session_impl::update_peer_fingerprint) + SET_NOPREV(peer_fingerprint, "-LT1110-", &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 2bea4ff41..5cfca912d 100644 --- a/src/string_util.cpp +++ b/src/string_util.cpp @@ -168,7 +168,7 @@ namespace libtorrent return static_cast(p) + (8 - offset); } - // this parses the string that's used as the liste_interfaces setting. + // 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 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 dba79c27b..a79f4e71c 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -199,6 +199,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); @@ -208,6 +209,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 r = ses.is_dht_running(); TEST_CHECK(r); @@ -219,6 +221,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); bool r = ses.is_dht_running(); diff --git a/test/test_direct_dht.cpp b/test/test_direct_dht.cpp index c0887d067..5d2392b0f 100644 --- a/test/test_direct_dht.cpp +++ b/test/test_direct_dht.cpp @@ -94,6 +94,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); @@ -116,6 +117,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_ip_filter.cpp b/test/test_ip_filter.cpp index bdf6c252c..21ac40448 100644 --- a/test/test_ip_filter.cpp +++ b/test/test_ip_filter.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "test.hpp" +#include "settings.hpp" #include "libtorrent/socket_io.hpp" #include "libtorrent/session.hpp" @@ -93,7 +94,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(boost::get<0>(ipf.export_filter()).size(), 1); diff --git a/test/test_magnet.cpp b/test/test_magnet.cpp index ecad3c3d8..df20dee86 100644 --- a/test/test_magnet.cpp +++ b/test/test_magnet.cpp @@ -38,13 +38,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/torrent_info.hpp" // for announce_entry #include "libtorrent/announce_entry.hpp" +#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; @@ -76,7 +77,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); @@ -177,7 +178,7 @@ TORRENT_TEST(magnet) TEST_EQUAL(to_hex(t.info_hash().to_string()), "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 1ba46063a..a38882570 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 @@ -374,7 +375,7 @@ done: TORRENT_TEST(priority) { using namespace libtorrent; - settings_pack p; + settings_pack p = settings(); test_transfer(p); cleanup(); } @@ -383,7 +384,7 @@ TORRENT_TEST(priority) // yet TORRENT_TEST(no_metadata_file_prio) { - settings_pack pack; + settings_pack pack = settings(); lt::session ses(pack); add_torrent_params addp; @@ -403,7 +404,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 776c2f72d..cac98752c 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 b81fbe7c6..4f6ef334f 100644 --- a/test/test_resume.cpp +++ b/test/test_resume.cpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" +#include "settings.hpp" using namespace libtorrent; namespace lt = libtorrent; @@ -193,7 +194,7 @@ void default_tests(torrent_status const& s) TORRENT_TEST(piece_priorities) { - lt::session ses; + lt::session ses(settings()); boost::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -239,7 +240,7 @@ TORRENT_TEST(piece_priorities) 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); @@ -251,7 +252,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(); @@ -264,7 +265,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(); @@ -278,7 +279,7 @@ TORRENT_TEST(zero_file_prio) { fprintf(stderr, "test_file_prio\n"); - lt::session ses; + lt::session ses(settings()); boost::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -317,7 +318,7 @@ void test_seed_mode(bool file_prio, bool pieces_have, bool piece_prio fprintf(stderr, "test_seed_mode file_prio: %d pieces_have: %d piece_prio: %d\n" , file_prio, pieces_have, piece_prio); - lt::session ses; + lt::session ses(settings()); boost::shared_ptr ti = generate_torrent(); add_torrent_params p; p.ti = ti; @@ -397,7 +398,7 @@ TORRENT_TEST(seed_mode_preserve) TORRENT_TEST(resume_save_load) { - lt::session ses; + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "123", ""); h.save_resume_data(); @@ -423,7 +424,7 @@ TORRENT_TEST(resume_save_load) TORRENT_TEST(resume_save_load_resume) { - lt::session ses; + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, 0, "", "123"); h.save_resume_data(); @@ -452,7 +453,7 @@ TORRENT_TEST(file_priorities_resume_override) // 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. - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, add_torrent_params::flag_override_resume_data, "", "123").file_priorities(); @@ -464,7 +465,7 @@ TORRENT_TEST(file_priorities_resume_override) TORRENT_TEST(file_priorities_resume) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "", "123").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -475,7 +476,7 @@ TORRENT_TEST(file_priorities_resume) TORRENT_TEST(file_priorities1) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "010").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -488,7 +489,7 @@ TORRENT_TEST(file_priorities1) TORRENT_TEST(file_priorities2) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "123").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -499,7 +500,7 @@ TORRENT_TEST(file_priorities2) TORRENT_TEST(file_priorities3) { - lt::session ses; + lt::session ses(settings()); std::vector file_priorities = test_resume_flags(ses, 0, "4321").file_priorities(); TEST_EQUAL(file_priorities.size(), 3); @@ -510,7 +511,7 @@ TORRENT_TEST(file_priorities3) TORRENT_TEST(plain) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, 0).status(); default_tests(s); @@ -533,7 +534,7 @@ TORRENT_TEST(plain) TORRENT_TEST(use_resume_save_path) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_use_resume_save_path).status(); default_tests(s); #ifdef TORRENT_WINDOWS @@ -555,7 +556,7 @@ TORRENT_TEST(use_resume_save_path) TORRENT_TEST(override_resume_data) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_override_resume_data | add_torrent_params::flag_paused).status(); @@ -580,7 +581,7 @@ TORRENT_TEST(override_resume_data) TORRENT_TEST(seed_mode) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_override_resume_data | add_torrent_params::flag_seed_mode).status(); default_tests(s); @@ -603,7 +604,7 @@ TORRENT_TEST(seed_mode) TORRENT_TEST(upload_mode) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses, add_torrent_params::flag_upload_mode).status(); default_tests(s); #ifdef TORRENT_WINDOWS @@ -625,7 +626,7 @@ TORRENT_TEST(upload_mode) TORRENT_TEST(share_mode) { - lt::session ses; + lt::session ses(settings()); torrent_status s = test_resume_flags(ses , add_torrent_params::flag_override_resume_data | add_torrent_params::flag_share_mode).status(); @@ -649,7 +650,7 @@ TORRENT_TEST(share_mode) TORRENT_TEST(auto_managed) { - lt::session ses; + 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); @@ -672,7 +673,7 @@ TORRENT_TEST(auto_managed) TORRENT_TEST(paused) { - lt::session ses; + 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); @@ -701,7 +702,7 @@ TORRENT_TEST(url_seed_resume_data) { // merge url seeds with resume data fprintf(stderr, "flags: merge_resume_http_seeds\n"); - lt::session ses; + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, add_torrent_params::flag_merge_resume_http_seeds); std::set us = h.url_seeds(); @@ -724,7 +725,7 @@ TORRENT_TEST(resume_override_torrent) { // resume data overrides the .torrent_file fprintf(stderr, "flags: no merge_resume_http_seed\n"); - lt::session ses; + lt::session ses(settings()); torrent_handle h = test_resume_flags(ses, add_torrent_params::flag_merge_resume_trackers); std::set us = h.url_seeds(); diff --git a/test/test_session.cpp b/test/test_session.cpp index 21a88f6bb..fec541ad0 100644 --- a/test/test_session.cpp +++ b/test/test_session.cpp @@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bdecode.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/torrent_info.hpp" +#include "settings.hpp" #include @@ -55,11 +56,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); @@ -103,7 +104,7 @@ TORRENT_TEST(session) TORRENT_TEST(load_empty_file) { - settings_pack p; + settings_pack p = settings(); p.set_int(settings_pack::alert_mask, ~0); lt::session ses(p); @@ -135,7 +136,7 @@ TORRENT_TEST(session_stats) TORRENT_TEST(paused_session) { - lt::session s; + lt::session s(settings()); s.pause(); lt::add_torrent_params ps; @@ -160,14 +161,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_torrent.cpp b/test/test_torrent.cpp index fd7adb108..1659e91bd 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/extensions.hpp" +#include "settings.hpp" #include #include #include @@ -52,7 +53,7 @@ namespace lt = libtorrent; void test_running_torrent(boost::shared_ptr info, boost::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); @@ -189,7 +190,7 @@ TORRENT_TEST(total_wanted) boost::shared_ptr info(boost::make_shared( &tmp[0], tmp.size(), boost::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); @@ -227,7 +228,7 @@ TORRENT_TEST(added_peers) boost::shared_ptr info(boost::make_shared( &tmp[0], tmp.size(), boost::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); @@ -356,7 +357,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_web_seed_redirect.cpp b/test/test_web_seed_redirect.cpp index 5d90a8190..860820e34 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) , 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) From debf3c6e3688aab8394fe5c47737625faffe6f9e Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sun, 21 Aug 2016 14:43:44 -0400 Subject: [PATCH 8/8] update puff.c for gzip inflation (#1022) update puff.c for gzip inflation --- ChangeLog | 1 + include/libtorrent/puff.hpp | 8 +- src/gzip.cpp | 4 +- src/puff.cpp | 283 ++++++++++++++++++------------------ test/Jamfile | 4 +- test/Makefile.am | 1 + test/corrupt.gz | Bin 0 -> 296 bytes test/test_gzip.cpp | 18 ++- 8 files changed, 166 insertions(+), 153 deletions(-) create mode 100644 test/corrupt.gz diff --git a/ChangeLog b/ChangeLog index 6ac1549b1..e4c6f2fca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 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 diff --git a/include/libtorrent/puff.hpp b/include/libtorrent/puff.hpp index 7b2c4eab8..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 */ - boost::uint32_t *destlen, /* amount of output space */ - const unsigned char *source, /* pointer to source data pointer */ - boost::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/src/gzip.cpp b/src/gzip.cpp index d458e08f7..637d5cfd5 100644 --- a/src/gzip.cpp +++ b/src/gzip.cpp @@ -212,9 +212,9 @@ namespace libtorrent // start off with 4 kilobytes and grow // if needed - boost::uint32_t destlen = 4096; + unsigned long destlen = 4096; int ret = 0; - boost::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 dcaef91bb..83e1b0e26 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 boost::int16_t -and all "long" with boost::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 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 */ - boost::uint32_t outlen; /* available space at out */ - boost::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 */ - boost::uint32_t inlen; /* available input at in */ - boost::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) { - boost::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 |= (boost::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 { - boost::int16_t *count; /* number of symbols of each length */ - boost::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 */ - boost::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, boost::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 */ - boost::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, boost::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, boost::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 boost::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 boost::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 boost::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 boost::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 boost::int16_t lencnt[MAXBITS+1], lensym[FIXLCODES]; - static boost::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; - boost::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 */ - boost::int16_t lengths[MAXCODES]; /* descriptor code lengths */ - boost::int16_t lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ - boost::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 boost::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; @@ -669,12 +709,15 @@ local int dynamic(struct state *s) int len; /* last length to repeat */ symbol = decode(s, &lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ if (symbol < 16) /* length in 0..15 */ lengths[index++] = symbol; else { /* repeat instruction */ len = 0; /* 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,9 +795,9 @@ local int dynamic(struct state *s) * expected values to check. */ int puff(unsigned char *dest, /* pointer to destination pointer */ - boost::uint32_t *destlen, /* amount of output space */ - const unsigned char *source, /* pointer to source data pointer */ - boost::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 */ @@ -775,11 +823,15 @@ int puff(unsigned char *dest, /* pointer to destination pointer */ do { 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 */ + 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, boost::uint32_t *len) -{ - boost::uint32_t size; - unsigned char *buf; - FILE *in; - struct stat s; - - *len = 0; - if (stat(name, &s)) return NULL; - if ((s.st_mode & S_IFMT) != S_IFREG) return NULL; - size = (boost::uint32_t)(s.st_size); - if (size == 0 || (off_t)size != s.st_size) return NULL; - in = fopen(name, "r"); - if (in == NULL) return NULL; - buf = malloc(size); - if (buf != NULL && fread(buf, 1, size, in) != size) { - free(buf); - buf = NULL; - } - fclose(in); - *len = size; - return buf; -} - -int main(int argc, char **argv) -{ - int ret; - unsigned char *source; - boost::uint32_t len, sourcelen, destlen; - - if (argc < 2) return 2; - source = yank(argv[1], &len); - if (source == NULL) return 2; - sourcelen = len; - ret = puff(NIL, &destlen, source, &sourcelen); - if (ret) - printf("puff() failed with return code %d\n", ret); - else { - printf("puff() succeeded uncompressing %lu bytes\n", destlen); - if (sourcelen < len) printf("%lu compressed bytes unused\n", - len - sourcelen); - } - free(source); - return ret; -} -#endif - -#include "libtorrent/aux_/disable_warnings_pop.hpp" - diff --git a/test/Jamfile b/test/Jamfile index 8bbdb4b75..b5e69338a 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -91,7 +91,6 @@ test-suite libtorrent : test_socket_io.cpp # test_random.cpp test_utf8.cpp - test_gzip.cpp test_bitfield.cpp test_part_file.cpp test_peer_list.cpp @@ -123,6 +122,7 @@ test-suite libtorrent : test_linked_list.cpp test_file_progress.cpp ] + [ run test_gzip.cpp ] [ run test_receive_buffer.cpp ] [ run test_alert_manager.cpp ] [ run test_direct_dht.cpp ] @@ -188,6 +188,7 @@ alias win-tests : test_resume test_tracker test_checking + test_gzip ; # the openssl test hangs on the travis osx machine. difficult to debug @@ -227,6 +228,7 @@ alias osx-tests : test_time_critical test_pex test_priority + test_gzip ; explicit win-tests ; diff --git a/test/Makefile.am b/test/Makefile.am index 40577945f..f4695c899 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -115,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 0000000000000000000000000000000000000000..9ed0b14bf3eee158f1a53bd977a8a919f1fd741e GIT binary patch literal 296 zcmb2|=3wA>oRE|hS=zwBz>p9L2C+Zz1BQPbJRIDoXYxcc|4&L{_|M7!WU@k;{~7k| zQD9)0jtUqUAVx>h((FivUoeNkTm!W=GLoU;|9>clfU2aVBmtHbhi_ojJUl$WAaVf! DT@aBF literal 0 HcmV?d00001 diff --git a/test/test_gzip.cpp b/test/test_gzip.cpp index f605d48c5..45177ef97 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); +} +