diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 024d9760..78f9e028 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -21,7 +21,7 @@ env: BOOST_VERSION: 1.77.0 BOOST_PATH: ${{github.workspace}}/../install/boost/ #rem qt_standard_project_setup() was introduced in Qt 6.3. - Qt6_VERSION: 6.3.1 + Qt6_VERSION: 6.5.3 LibtorrentRasterbar_SOURCE_DIR: ${{github.workspace}}/3rd/libtorrent-rasterbar LibtorrentRasterbar_BUILD_DIR: ${{github.workspace}}/00/build/libtorrent-rasterbar LibtorrentRasterbar_INSTALL_DIR: ${{github.workspace}}/00/install/libtorrent-rasterbar @@ -92,7 +92,7 @@ jobs: qt_host: 'linux' qt_target: 'desktop' qt_arch: 'gcc_64' - qt_tools: 'tools_openssl_x64' + qt_tools: '' # To build OpenSSLv3: 'tools_opensslv3_src' Qt6_CUSTOM_INSTALL_PATH: "/home/runner/work/DownZemAll/qt/" DIRECTIVE_CMAKE_GENERATOR: '' INSTALL_BOOST_PLATFORM_VERSION: '18.04' # 18.04, 20.04 Rem: Ubuntu 20.04 doesn't have Boost 1.77.0 @@ -102,7 +102,7 @@ jobs: qt_host: 'windows' qt_target: 'desktop' qt_arch: 'win64_mingw' - qt_tools: 'tools_openssl_x64' + qt_tools: 'tools_opensslv3_x64' Qt6_CUSTOM_INSTALL_PATH: "D:\\a\\DownZemAll\\qt\\" DIRECTIVE_CMAKE_GENERATOR: '-G "MinGW Makefiles"' INSTALL_BOOST_PLATFORM_VERSION: '2019' # 2019, 2022 @@ -246,7 +246,8 @@ jobs: arch: ${{matrix.INSTALL_BOOST_ARCH}} cache: true - - name: List files in Boost + - name: List files in Boost (if Debug Logging is enabled) + if: runner.debug == '1' shell: bash env: Installed_Boost_VER: ${{ steps.install-boost.outputs.Boost_VER }} @@ -261,8 +262,9 @@ jobs: - name: Install Qt uses: jurplel/install-qt-action@v3 # Rem: Once installed, ${{env.Qt6_DIR}} is set. + # https://ddalcino.github.io/aqt-list-server/ with: - aqtversion: '==2.1.*' + aqtversion: '==3.1.*' version: ${{env.Qt6_VERSION}} dir: ${{matrix.Qt6_CUSTOM_INSTALL_PATH}} host: ${{matrix.qt_host}} @@ -271,7 +273,8 @@ jobs: tools: ${{matrix.qt_tools}} cache: true - - name: List files in Qt + - name: List files in Qt (if Debug Logging is enabled) + if: runner.debug == '1' shell: bash run: cd "${{env.Qt6_DIR}}/../../" && ls -alR # env.Qt6_DIR @@ -282,6 +285,24 @@ jobs: # The thing is that "env.Qt6_DIR" is defined only at runtime, *after* install-qt-action has run. id: qt6openssl shell: python + # 2 versions present in Ubuntu: + # * Default version (3.0.2-0ubuntu1.12) + # in /usr/ (see "apt list libssl-dev") + # => openssl_dir = os.path.normpath("/usr") + # + # * Qt6 version (3.0.12) + # To build it: + # openssl_dir = os.path.normpath(os.path.join(r"${{env.Qt6_DIR}}", "..", "..", "Tools", "OpenSSLv3", "src")) + # cd "${{openssl_dir}}" + # ./config + # make + # make test + # sudo make install_sw + # Then: + # openssl_dir = os.path.normpath(os.path.join(r"${{env.Qt6_DIR}}", "..", "..", "Tools", "OpenSSLv3", "src")) + # openssl_lib_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libcrypto.a")) + # openssl_ssl_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libssl.a")) + # run: | import os @@ -290,14 +311,14 @@ jobs: # ssleay32 -> libssl if "${{ matrix.os }}" == "windows-latest": - openssl_dir = os.path.normpath(os.path.join(r"${{env.Qt6_DIR}}", "..", "..", "Tools", "OpenSSL", "Win_x64")) + openssl_dir = os.path.normpath(os.path.join(r"${{env.Qt6_DIR}}", "..", "..", "Tools", "OpenSSLv3", "Win_x64")) openssl_lib_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libcrypto.lib")) openssl_ssl_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libssl.lib")) if "${{ matrix.os }}" == "ubuntu-latest": - openssl_dir = os.path.normpath(os.path.join(r"${{env.Qt6_DIR}}", "..", "..", "Tools", "OpenSSL", "binary")) - openssl_lib_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libcrypto.a")) - openssl_ssl_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "libssl.a")) + openssl_dir = os.path.normpath("/usr") + openssl_lib_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "x86_64-linux-gnu", "libcrypto.a")) + openssl_ssl_eay = os.path.normpath(os.path.join(openssl_dir, "lib", "x86_64-linux-gnu", "libssl.a")) if "GITHUB_OUTPUT" in os.environ: with open(os.environ["GITHUB_OUTPUT"], "a") as f: @@ -305,7 +326,8 @@ jobs: print(f"OpenSSL_LIB_EAY={ openssl_lib_eay }", file=f) print(f"OpenSSL_SSL_EAY={ openssl_ssl_eay }", file=f) - - name: List files in OpenSSL + - name: List files in OpenSSL (if Debug Logging is enabled) + if: runner.debug == '1' shell: bash env: OpenSSL_ROOT_DIR: ${{ steps.qt6openssl.outputs.OpenSSL_ROOT_DIR }} @@ -357,7 +379,8 @@ jobs: working-directory: "${{env.LibtorrentRasterbar_BUILD_DIR}}" run: cmake --build . --target install - - name: List files in Libtorrent + - name: List files in Libtorrent (if Debug Logging is enabled) + if: runner.debug == '1' shell: bash run: cd "${{env.LibtorrentRasterbar_INSTALL_DIR}}" && ls -alR @@ -517,30 +540,35 @@ jobs: os.makedirs(directory) - name: Download Chromium Addon + continue-on-error: true uses: actions/download-artifact@v3 with: name: artifact_chromium path: "${{env.Project_RELEASE_DIR}}" - name: Download Firefox Addon + continue-on-error: true uses: actions/download-artifact@v3 with: name: artifact_firefox path: "${{env.Project_RELEASE_DIR}}" - name: Download Linux Portable + continue-on-error: true uses: actions/download-artifact@v3 with: name: artifact_linux_portable path: "${{env.Project_RELEASE_DIR}}" - name: Download Windows MinGW 64 Portable + continue-on-error: true uses: actions/download-artifact@v3 with: name: artifact_windows_mingw_64_portable path: "${{env.Project_RELEASE_DIR}}" - name: Download Windows 64 Installer + continue-on-error: true uses: actions/download-artifact@v3 with: name: artifact_windows_64_installer diff --git a/3rd/libtorrent-rasterbar/CMakeLists.txt b/3rd/libtorrent-rasterbar/CMakeLists.txt index c3609147..5477543b 100644 --- a/3rd/libtorrent-rasterbar/CMakeLists.txt +++ b/3rd/libtorrent-rasterbar/CMakeLists.txt @@ -544,11 +544,6 @@ if(static_runtime) set(OPENSSL_MSVC_STATIC_RT ON) endif() -if (NOT BUILD_SHARED_LIBS) - set(Boost_USE_STATIC_LIBS ON) - set(OPENSSL_USE_STATIC_LIBS ON) -endif() - add_library(torrent-rasterbar ${sources} ${try_signal_sources} @@ -618,7 +613,7 @@ if (WIN32) debug dbghelp crypt32 ) - add_definitions(-D_WIN32_WINNT=0x0600) # target Windows Vista or later + add_definitions(-D_WIN32_WINNT=0x0601) # target Windows 7 or later target_compile_definitions(torrent-rasterbar PUBLIC WIN32_LEAN_AND_MEAN # prevent winsock1 to be included diff --git a/3rd/libtorrent-rasterbar/ChangeLog b/3rd/libtorrent-rasterbar/ChangeLog index fa017832..4006b7b1 100644 --- a/3rd/libtorrent-rasterbar/ChangeLog +++ b/3rd/libtorrent-rasterbar/ChangeLog @@ -1,7 +1,37 @@ - * fix uTP streams timing out instead of closing cleanly +2.0.9 released + + * fix issue with web seed connections when they close and re-open + * fallocate() not supported is not a fatal error + * fix proxying of IPv6 connections via IPv4 proxy + * treat CGNAT address range as local IPs + * add stricter checking of piece layers when loading torrents + * add stricter checking of v1 and v2 hashes being consistent + * cache failed DNS lookups as well as successful ones + * add an i2p torrent state to control interactions with clear swarms + * fix i2p SAM protocol parsing of quoted messages + * expose i2p peer destination in peer_info + * fix i2p tracker announces + * fix issue with read_piece() stopping torrent on pieces not yet downloaded + * improve handling of allow_i2p_mixed setting to work for magnet links + * fix web seed request for renamed single-file torrents + * fix issue where web seeds could disappear from resume data + * extend save_resume with additional conditional flags + * fix issue with retrying trackers in tiers > 0 + * fix last_upload and last_download resume data fields to use posix time + * improve error messages for no_connect_privileged_ports, by untangle it from the port filter + * fix I2P issue introduced in 2.0.0 + * add async tracker status query, post_trackers() + * add async torrent status query, post_status() + * support loading version 2 of resume data format + * fix issue with odd piece sizes + * add async piece availability query, post_piece_availability() + * add async download queue query, post_download_queue() + * add async file_progress query, post_file_progress() + * add async peer_info query, post_peer_info() 2.0.8 released + * fix uTP streams timing out instead of closing cleanly * add write_torrent_file_buf() overload for generating .torrent files * add create_torrent::generate_buf() function to generate into a buffer * fix copy_file when the file ends with a sparse region diff --git a/3rd/libtorrent-rasterbar/Jamfile b/3rd/libtorrent-rasterbar/Jamfile index eceda71b..a9e121a3 100644 --- a/3rd/libtorrent-rasterbar/Jamfile +++ b/3rd/libtorrent-rasterbar/Jamfile @@ -12,7 +12,7 @@ import cast ; # we need version numbers in the form X.Y.Z in order to trigger the built-in # support for generating symlinks to the installed library -VERSION = 2.0.8 ; +VERSION = 2.0.9 ; BOOST_ROOT = [ modules.peek : BOOST_ROOT ] ; CXXFLAGS = [ modules.peek : CXXFLAGS ] ; @@ -206,6 +206,13 @@ rule linking ( properties * ) result += boost_system ; } + if ! windows in $(properties) + { + # MingW defines a macro called "stat" if this is set, which causes build + # failures + result += _FILE_OFFSET_BITS=64 ; + } + result += BOOST_ALL_NO_LIB BOOST_MULTI_INDEX_DISABLE_SERIALIZATION BOOST_SYSTEM_NO_DEPRECATED @@ -405,6 +412,7 @@ rule openssl-lib-path ( properties * ) local address_model = [ feature.get-values : $(properties) ] ; OPENSSL_LIB += "C:/Program Files/OpenSSL-Win$(address_model)/lib" ; OPENSSL_LIB += "C:/Program Files (x86)/OpenSSL-Win$(address_model)/lib" ; + OPENSSL_LIB += "C:/Program Files/OpenSSL/lib" ; } local result ; @@ -432,6 +440,7 @@ rule openssl-include-path ( properties * ) local address_model = [ feature.get-values : $(properties) ] ; OPENSSL_INCLUDE += "C:/Program Files/OpenSSL-Win$(address_model)/include" ; OPENSSL_INCLUDE += "C:/Program Files (x86)/OpenSSL-Win$(address_model)/include" ; + OPENSSL_INCLUDE += "C:/Program Files/OpenSSL/include" ; } local result ; @@ -547,7 +556,7 @@ feature.compose on : TORRENT_USE_ASSERTS=1 ; feature.compose production : TORRENT_USE_ASSERTS=1 TORRENT_PRODUCTION_ASSERTS=1 ; feature.compose system : TORRENT_USE_ASSERTS=1 TORRENT_USE_SYSTEM_ASSERTS=1 ; -feature windows-version : vista win7 win10 xp : composite propagated ; +feature windows-version : win7 win10 vista xp : composite propagated ; feature.compose vista : _WIN32_WINNT=0x0600 ; feature.compose win7 : _WIN32_WINNT=0x0601 ; feature.compose win10 : _WIN32_WINNT=0x0A00 ; @@ -883,7 +892,6 @@ local usage-requirements = ./include ./include/libtorrent release:NDEBUG - _FILE_OFFSET_BITS=64 # enable cancel support in asio BOOST_ASIO_ENABLE_CANCELIO # make sure asio uses std::chrono diff --git a/3rd/libtorrent-rasterbar/Makefile b/3rd/libtorrent-rasterbar/Makefile index e831d7bb..e3f43e88 100644 --- a/3rd/libtorrent-rasterbar/Makefile +++ b/3rd/libtorrent-rasterbar/Makefile @@ -1,4 +1,4 @@ -VERSION=2.0.8 +VERSION=2.0.9 BUILD_CONFIG=release link=shared crypto=openssl warnings=off address-model=64 @@ -776,7 +776,9 @@ SIM_SOURCES = \ test_torrent_status.cpp \ test_tracker.cpp \ test_transfer.cpp \ - test_transfer_matrix.cpp \ + test_transfer_full_invalid_files.cpp \ + test_transfer_no_files.cpp \ + test_transfer_partial_valid_files.cpp \ test_utp.cpp \ test_web_seed.cpp \ transfer_sim.hpp \ @@ -1059,7 +1061,9 @@ TEST_TORRENTS = \ v2_incomplete_piece_layer.torrent \ v2_invalid_pad_file.torrent \ v2_invalid_piece_layer.torrent \ + v2_invalid_piece_layer_root.torrent \ v2_invalid_piece_layer_size.torrent \ + v2_unknown_piece_layer_entry.torrent \ v2_multiple_files.torrent \ v2_bad_file_alignment.torrent \ v2_unordered_files.torrent \ diff --git a/3rd/libtorrent-rasterbar/bindings/python/CMakeLists.txt b/3rd/libtorrent-rasterbar/bindings/python/CMakeLists.txt index a9145ae2..2f4de485 100644 --- a/3rd/libtorrent-rasterbar/bindings/python/CMakeLists.txt +++ b/3rd/libtorrent-rasterbar/bindings/python/CMakeLists.txt @@ -19,7 +19,7 @@ cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR) # Configurable policies: <= C # See https://devguide.python.org/#status-of-python-branches for supported python versions function(_get_compatible_python_versions _ret) if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20) - list(APPEND _tmp 3.6 3.7 3.8 3.9 3.10) + list(APPEND _tmp 3.6 3.7 3.8 3.9 3.10 3.11) endif() set(${_ret} ${_tmp} PARENT_SCOPE) endfunction() diff --git a/3rd/libtorrent-rasterbar/bindings/python/src/alert.cpp b/3rd/libtorrent-rasterbar/bindings/python/src/alert.cpp index c51635ca..b93b9a39 100644 --- a/3rd/libtorrent-rasterbar/bindings/python/src/alert.cpp +++ b/3rd/libtorrent-rasterbar/bindings/python/src/alert.cpp @@ -1153,6 +1153,30 @@ void bind_alert() .add_property("metadata", make_getter(&torrent_conflict_alert::metadata, by_value())) ; + class_, noncopyable>( + "peer_info_alert", no_init) + .add_property("peer_info", make_getter(&peer_info_alert::peer_info, by_value())) + ; + + class_, noncopyable>( + "file_progress_alert", no_init) + .add_property("files", make_getter(&file_progress_alert::files, by_value())) + ; + + class_, noncopyable>( + "piece_info_alert", no_init) + .add_property("piece_info", make_getter(&piece_info_alert::piece_info, by_value())) + ; + + class_, noncopyable>( + "piece_availability_alert", no_init) + .add_property("piece_availability", make_getter(&piece_availability_alert::piece_availability, by_value())) + ; + + class_, noncopyable>( + "tracker_list_alert", no_init) + .add_property("trackers", make_getter(&tracker_list_alert::trackers, by_value())) + ; } #ifdef _MSC_VER diff --git a/3rd/libtorrent-rasterbar/bindings/python/src/peer_info.cpp b/3rd/libtorrent-rasterbar/bindings/python/src/peer_info.cpp index 07923952..a8bd773f 100644 --- a/3rd/libtorrent-rasterbar/bindings/python/src/peer_info.cpp +++ b/3rd/libtorrent-rasterbar/bindings/python/src/peer_info.cpp @@ -108,6 +108,9 @@ void bind_peer_info() .def_readonly("estimated_reciprocation_rate", &peer_info::estimated_reciprocation_rate) #endif .add_property("local_endpoint", get_local_endpoint) +#if TORRENT_USE_I2P + .def("i2p_destination", &peer_info::i2p_destination) +#endif ; // flags @@ -120,6 +123,7 @@ void bind_peer_info() pi.attr("outgoing_connection") = peer_info::outgoing_connection; pi.attr("handshake") = peer_info::handshake; pi.attr("connecting") = peer_info::connecting; + pi.attr("i2p_socket") = peer_info::i2p_socket; #if TORRENT_ABI_VERSION == 1 pi.attr("queued") = peer_info::queued; #endif diff --git a/3rd/libtorrent-rasterbar/bindings/python/src/session.cpp b/3rd/libtorrent-rasterbar/bindings/python/src/session.cpp index 75e77bc8..1a597129 100644 --- a/3rd/libtorrent-rasterbar/bindings/python/src/session.cpp +++ b/3rd/libtorrent-rasterbar/bindings/python/src/session.cpp @@ -128,7 +128,7 @@ namespace throw_error_already_set(); } - TORRENT_TRY + try { // if the dictionary doesn't contain "key", it will throw, hence // the try-catch here @@ -153,7 +153,7 @@ namespace break; } } - TORRENT_CATCH(...) {} + catch (...) {} } } @@ -407,14 +407,16 @@ namespace add_torrent_params p; dict_to_add_torrent_params(params, p); + if (p.save_path.empty()) + { + PyErr_SetString(PyExc_KeyError, + "save_path must be set in add_torrent_params"); + throw_error_already_set(); + } + allow_threading_guard guard; -#ifndef BOOST_NO_EXCEPTIONS return s.add_torrent(std::move(p)); -#else - error_code ec; - return s.add_torrent(std::move(p), ec); -#endif } void async_add_torrent(lt::session& s, dict params) @@ -422,6 +424,13 @@ namespace add_torrent_params p; dict_to_add_torrent_params(params, p); + if (p.save_path.empty()) + { + PyErr_SetString(PyExc_KeyError, + "save_path must be set in add_torrent_params"); + throw_error_already_set(); + } + allow_threading_guard guard; s.async_add_torrent(std::move(p)); @@ -433,14 +442,16 @@ namespace if (p.ti) atp.ti = std::make_shared(*p.ti); + if (p.save_path.empty()) + { + PyErr_SetString(PyExc_KeyError, + "save_path must be set in add_torrent_params"); + throw_error_already_set(); + } + allow_threading_guard guard; -#ifndef BOOST_NO_EXCEPTIONS return s.add_torrent(std::move(p)); -#else - error_code ec; - return s.add_torrent(std::move(p), ec); -#endif } void wrap_async_add_torrent(lt::session& s, lt::add_torrent_params const& p) @@ -449,6 +460,13 @@ namespace if (p.ti) atp.ti = std::make_shared(*p.ti); + if (p.save_path.empty()) + { + PyErr_SetString(PyExc_ValueError, + "save_path must be set in add_torrent_params"); + throw_error_already_set(); + } + allow_threading_guard guard; s.async_add_torrent(std::move(p)); diff --git a/3rd/libtorrent-rasterbar/bindings/python/src/torrent_handle.cpp b/3rd/libtorrent-rasterbar/bindings/python/src/torrent_handle.cpp index 6bde5b4d..12fcbca9 100644 --- a/3rd/libtorrent-rasterbar/bindings/python/src/torrent_handle.cpp +++ b/3rd/libtorrent-rasterbar/bindings/python/src/torrent_handle.cpp @@ -457,6 +457,9 @@ void bind_torrent_handle() void (torrent_handle::*move_storage0)(std::string const&, lt::move_flags_t) const = &torrent_handle::move_storage; void (torrent_handle::*rename_file0)(file_index_t, std::string const&) const = &torrent_handle::rename_file; + bool (torrent_handle::*need_save_resume_data0)() const = &torrent_handle::need_save_resume_data; + bool (torrent_handle::*need_save_resume_data1)(resume_data_flags_t) const = &torrent_handle::need_save_resume_data; + std::vector (torrent_handle::*file_status0)() const = &torrent_handle::file_status; #define _ allow_threads @@ -482,10 +485,15 @@ void bind_torrent_handle() .def(self < self) .def("__hash__", (std::size_t (*)(torrent_handle const&))&libtorrent::hash_value) .def("get_peer_info", get_peer_info) + .def("post_peer_info", &torrent_handle::post_peer_info) .def("status", _(&torrent_handle::status), arg("flags") = 0xffffffff) + .def("post_status", &torrent_handle::post_status, arg("flags") = 0xffffffff) .def("get_download_queue", get_download_queue) + .def("post_download_queue", &torrent_handle::post_download_queue) .def("file_progress", file_progress, arg("flags") = file_progress_flags_t{}) + .def("post_file_progress", &torrent_handle::post_file_progress, arg("flags") = file_progress_flags_t{}) .def("trackers", trackers) + .def("post_trackers", &torrent_handle::post_trackers) .def("replace_trackers", replace_trackers) .def("add_tracker", add_tracker) .def("add_url_seed", _(&torrent_handle::add_url_seed)) @@ -515,6 +523,7 @@ void bind_torrent_handle() .def("reset_piece_deadline", _(&torrent_handle::reset_piece_deadline), (arg("index"))) .def("clear_piece_deadlines", _(&torrent_handle::clear_piece_deadlines), (arg("index"))) .def("piece_availability", &piece_availability) + .def("post_piece_availability", &torrent_handle::post_piece_availability) .def("piece_priority", _(piece_priority0)) .def("piece_priority", _(piece_priority1)) .def("prioritize_pieces", &prioritize_pieces) @@ -525,7 +534,8 @@ void bind_torrent_handle() .def("file_priority", &file_prioritity1) .def("file_status", _(file_status0)) .def("save_resume_data", _(&torrent_handle::save_resume_data), arg("flags") = 0) - .def("need_save_resume_data", _(&torrent_handle::need_save_resume_data)) + .def("need_save_resume_data", _(need_save_resume_data0)) + .def("need_save_resume_data", _(need_save_resume_data1), arg("flags")) .def("force_reannounce", _(force_reannounce0) , (arg("seconds") = 0, arg("tracker_idx") = -1, arg("flags") = reannounce_flags_t{})) #ifndef TORRENT_DISABLE_DHT diff --git a/3rd/libtorrent-rasterbar/docs/building.html b/3rd/libtorrent-rasterbar/docs/building.html index ce1feb74..f8067a68 100644 --- a/3rd/libtorrent-rasterbar/docs/building.html +++ b/3rd/libtorrent-rasterbar/docs/building.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,35 +25,35 @@ Version: -2.0.8 +2.0.9
diff --git a/3rd/libtorrent-rasterbar/docs/client_test.html b/3rd/libtorrent-rasterbar/docs/client_test.html index f163a764..7235b131 100644 --- a/3rd/libtorrent-rasterbar/docs/client_test.html +++ b/3rd/libtorrent-rasterbar/docs/client_test.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,7 +25,7 @@

client_test example program

Version: -2.0.8 +2.0.9

Client test is a, more or less, complete bittorrent client. It lacks most diff --git a/3rd/libtorrent-rasterbar/docs/contributing.html b/3rd/libtorrent-rasterbar/docs/contributing.html index fa1774e3..aaf69877 100644 --- a/3rd/libtorrent-rasterbar/docs/contributing.html +++ b/3rd/libtorrent-rasterbar/docs/contributing.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,13 +25,13 @@ Version: -2.0.8 +2.0.9

diff --git a/3rd/libtorrent-rasterbar/docs/dht_extensions.html b/3rd/libtorrent-rasterbar/docs/dht_extensions.html index 50d3bea8..286c9206 100644 --- a/3rd/libtorrent-rasterbar/docs/dht_extensions.html +++ b/3rd/libtorrent-rasterbar/docs/dht_extensions.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,7 +25,7 @@

Mainline DHT extensions

Version: -2.0.8 +2.0.9

libtorrent implements a few extensions to the Mainline DHT protocol.

diff --git a/3rd/libtorrent-rasterbar/docs/dht_rss.html b/3rd/libtorrent-rasterbar/docs/dht_rss.html index 62b8890d..46fe3f2d 100644 --- a/3rd/libtorrent-rasterbar/docs/dht_rss.html +++ b/3rd/libtorrent-rasterbar/docs/dht_rss.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,30 +25,30 @@

BitTorrent extension for DHT RSS feeds

Version: -2.0.8 +2.0.9

This proposal has been superseded by the dht_put feature. This may diff --git a/3rd/libtorrent-rasterbar/docs/dht_sec.html b/3rd/libtorrent-rasterbar/docs/dht_sec.html index ae2a7762..70ac3abd 100644 --- a/3rd/libtorrent-rasterbar/docs/dht_sec.html +++ b/3rd/libtorrent-rasterbar/docs/dht_sec.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,20 +25,20 @@ Version: -2.0.8 +2.0.9

diff --git a/3rd/libtorrent-rasterbar/docs/dht_store.html b/3rd/libtorrent-rasterbar/docs/dht_store.html index e5f00f3d..3551d6ef 100644 --- a/3rd/libtorrent-rasterbar/docs/dht_store.html +++ b/3rd/libtorrent-rasterbar/docs/dht_store.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,36 +25,36 @@

BitTorrent extension for arbitrary DHT store

Version: -2.0.8 +2.0.9

This is a proposal for an extension to the BitTorrent DHT to allow @@ -199,7 +199,7 @@

mutable items

 4:salt6:foobar3:seqi4e1:v12:Hello world!
 
-
+

put message

Request:

@@ -329,7 +329,7 @@ 

errors

critical feature in synchronization of multiple agents sharing an immutable item.

-
+

get message

Request:

diff --git a/3rd/libtorrent-rasterbar/docs/examples.html b/3rd/libtorrent-rasterbar/docs/examples.html
index 5471ae97..2a48c787 100644
--- a/3rd/libtorrent-rasterbar/docs/examples.html
+++ b/3rd/libtorrent-rasterbar/docs/examples.html
@@ -4,7 +4,7 @@
 
 
 
-
+
 libtorrent
 
 
@@ -25,16 +25,16 @@
 
 
 Version:
-2.0.8
+2.0.9
 
 
 

Table of contents

    -
  • examples @@ -237,13 +237,13 @@

    make_torrent

    switch (flag) { - case 'l': + case 'l': flags |= lt::create_torrent::symlinks; continue; - case '2': + case '2': flags |= lt::create_torrent::v2_only; continue; - case 'T': + case 'T': flags |= lt::create_torrent::modification_time; continue; } @@ -252,15 +252,15 @@

    make_torrent

    switch (flag) { - case 'w': web_seeds.push_back(args[1]); break; - case 't': trackers.push_back(args[1]); break; - case 's': piece_size = atoi(args[1]); break; - case 'o': outfile = args[1]; break; - case 'C': creator_str = args[1]; break; - case 'c': comment_str = args[1]; break; - case 'r': root_cert = args[1]; break; - case 'L': collections.push_back(args[1]); break; - case 'S': { + case 'w': web_seeds.push_back(args[1]); break; + case 't': trackers.push_back(args[1]); break; + case 's': piece_size = atoi(args[1]); break; + case 'o': outfile = args[1]; break; + case 'C': creator_str = args[1]; break; + case 'c': comment_str = args[1]; break; + case 'r': root_cert = args[1]; break; + case 'L': collections.push_back(args[1]); break; + case 'S': { if (strlen(args[1]) != 40) { std::cerr << "invalid info-hash for -S. " "Expected 40 hex characters\n"; @@ -383,7 +383,7 @@

    dump_torrent

    #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" -#include "libtorrent/torrent_info.hpp" +#include "libtorrent/load_torrent.hpp" #include "libtorrent/bdecode.hpp" #include "libtorrent/magnet_uri.hpp" #include "libtorrent/span.hpp" @@ -458,27 +458,36 @@

    dump_torrent

    } } - lt::torrent_info const t(filename, cfg); + lt::add_torrent_params const atp = lt::load_torrent_file(filename, cfg); // print info about torrent - if (!t.nodes().empty()) + if (!atp.dht_nodes.empty()) { std::printf("nodes:\n"); - for (auto const& i : t.nodes()) + for (auto const& i : atp.dht_nodes) std::printf("%s: %d\n", i.first.c_str(), i.second); } - if (!t.trackers().empty()) + if (!atp.trackers.empty()) { puts("trackers:\n"); - for (auto const& i : t.trackers()) - std::printf("%2d: %s\n", i.tier, i.url.c_str()); + auto tier_it = atp.tracker_tiers.begin(); + int tier = 0; + for (auto const& i : atp.trackers) + { + if (tier_it != atp.tracker_tiers.end()) + { + tier = *tier_it; + ++tier_it; + } + std::printf("%2d: %s\n", tier, i.c_str()); + } } std::stringstream ih; - ih << t.info_hashes().v1; - if (t.info_hashes().has_v2()) - ih << ", " << t.info_hashes().v2; + ih << atp.info_hashes.v1; + if (atp.info_hashes.has_v2()) + ih << ", " << atp.info_hashes.v2; std::printf("number of pieces: %d\n" "piece length: %d\n" "info hash: %s\n" @@ -488,15 +497,15 @@

    dump_torrent

    "name: %s\n" "number of files: %d\n" "files:\n" - , t.num_pieces() - , t.piece_length() + , atp.ti->num_pieces() + , atp.ti->piece_length() , ih.str().c_str() - , t.comment().c_str() - , t.creator().c_str() - , make_magnet_uri(t).c_str() - , t.name().c_str() - , t.num_files()); - lt::file_storage const& st = t.files(); + , atp.ti->comment().c_str() + , atp.ti->creator().c_str() + , make_magnet_uri(atp).c_str() + , atp.name.c_str() + , atp.ti->num_files()); + lt::file_storage const& st = atp.ti->files(); for (auto const i : st.file_range()) { auto const first = st.map_file(i, 0, 0).piece; @@ -522,12 +531,8 @@

    dump_torrent

    , (flags & lt::file_storage::flag_symlink) ? st.symlink(i).c_str() : ""); } std::printf("web seeds:\n"); - for (auto const& ws : t.web_seeds()) - { - std::printf("%s %s\n" - , ws.type == lt::web_seed_entry::url_seed ? "BEP19" : "BEP17" - , ws.url.c_str()); - } + for (auto const& ws : atp.url_seeds) + std::printf("%s\n", ws.c_str()); return 0; } diff --git a/3rd/libtorrent-rasterbar/docs/extension_protocol.html b/3rd/libtorrent-rasterbar/docs/extension_protocol.html index 8324f8ad..78d7e4a7 100644 --- a/3rd/libtorrent-rasterbar/docs/extension_protocol.html +++ b/3rd/libtorrent-rasterbar/docs/extension_protocol.html @@ -4,7 +4,7 @@ - + libtorrent diff --git a/3rd/libtorrent-rasterbar/docs/features-ref.html b/3rd/libtorrent-rasterbar/docs/features-ref.html index 58b1d336..d49d9621 100644 --- a/3rd/libtorrent-rasterbar/docs/features-ref.html +++ b/3rd/libtorrent-rasterbar/docs/features-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,30 +25,30 @@ Version: -2.0.8 +2.0.9
    diff --git a/3rd/libtorrent-rasterbar/docs/hacking.html b/3rd/libtorrent-rasterbar/docs/hacking.html index 51a41832..cfb948a3 100644 --- a/3rd/libtorrent-rasterbar/docs/hacking.html +++ b/3rd/libtorrent-rasterbar/docs/hacking.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,25 +25,25 @@

    libtorrent hacking

    Version: -2.0.8 +2.0.9

    This describe some of the internals of libtorrent. If you're looking for diff --git a/3rd/libtorrent-rasterbar/docs/header.rst b/3rd/libtorrent-rasterbar/docs/header.rst index a897ee0d..cdfef908 100644 --- a/3rd/libtorrent-rasterbar/docs/header.rst +++ b/3rd/libtorrent-rasterbar/docs/header.rst @@ -1 +1 @@ -:Version: 2.0.8 +:Version: 2.0.9 diff --git a/3rd/libtorrent-rasterbar/docs/img/cwnd_thumb.png b/3rd/libtorrent-rasterbar/docs/img/cwnd_thumb.png index 56979ab4..c9b7326e 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/cwnd_thumb.png and b/3rd/libtorrent-rasterbar/docs/img/cwnd_thumb.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/delays_thumb.png b/3rd/libtorrent-rasterbar/docs/img/delays_thumb.png index 2d980a3e..7f0a6e0d 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/delays_thumb.png and b/3rd/libtorrent-rasterbar/docs/img/delays_thumb.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/hacking.png b/3rd/libtorrent-rasterbar/docs/img/hacking.png index dc31245d..b9ff7309 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/hacking.png and b/3rd/libtorrent-rasterbar/docs/img/hacking.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/our_delay_base_thumb.png b/3rd/libtorrent-rasterbar/docs/img/our_delay_base_thumb.png index f4193f71..d9dc9ca0 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/our_delay_base_thumb.png and b/3rd/libtorrent-rasterbar/docs/img/our_delay_base_thumb.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/read_disk_buffers.png b/3rd/libtorrent-rasterbar/docs/img/read_disk_buffers.png index 1ee3623c..2989b6c8 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/read_disk_buffers.png and b/3rd/libtorrent-rasterbar/docs/img/read_disk_buffers.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/screenshot_thumb.png b/3rd/libtorrent-rasterbar/docs/img/screenshot_thumb.png index 3f3344aa..79726425 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/screenshot_thumb.png and b/3rd/libtorrent-rasterbar/docs/img/screenshot_thumb.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/storage.png b/3rd/libtorrent-rasterbar/docs/img/storage.png index 28b8ee7e..7d15a92a 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/storage.png and b/3rd/libtorrent-rasterbar/docs/img/storage.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/troubleshooting.png b/3rd/libtorrent-rasterbar/docs/img/troubleshooting.png index a35669a1..f6a27bb8 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/troubleshooting.png and b/3rd/libtorrent-rasterbar/docs/img/troubleshooting.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/troubleshooting_thumb.png b/3rd/libtorrent-rasterbar/docs/img/troubleshooting_thumb.png index a3f229a1..1e6fdf5e 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/troubleshooting_thumb.png and b/3rd/libtorrent-rasterbar/docs/img/troubleshooting_thumb.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/utp_stack.png b/3rd/libtorrent-rasterbar/docs/img/utp_stack.png index bf1ebcb5..07090ed2 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/utp_stack.png and b/3rd/libtorrent-rasterbar/docs/img/utp_stack.png differ diff --git a/3rd/libtorrent-rasterbar/docs/img/write_disk_buffers.png b/3rd/libtorrent-rasterbar/docs/img/write_disk_buffers.png index e2854a81..40c89ff4 100644 Binary files a/3rd/libtorrent-rasterbar/docs/img/write_disk_buffers.png and b/3rd/libtorrent-rasterbar/docs/img/write_disk_buffers.png differ diff --git a/3rd/libtorrent-rasterbar/docs/index.html b/3rd/libtorrent-rasterbar/docs/index.html index e11beb94..508109c0 100644 --- a/3rd/libtorrent-rasterbar/docs/index.html +++ b/3rd/libtorrent-rasterbar/docs/index.html @@ -4,7 +4,7 @@ - + libtorrent diff --git a/3rd/libtorrent-rasterbar/docs/manual-ref.html b/3rd/libtorrent-rasterbar/docs/manual-ref.html index 69a58491..bd184067 100644 --- a/3rd/libtorrent-rasterbar/docs/manual-ref.html +++ b/3rd/libtorrent-rasterbar/docs/manual-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,73 +25,73 @@ Version: -2.0.8 +2.0.9

    Table of contents

    @@ -496,6 +496,9 @@

    file format

    file-format string: "libtorrent resume file" +file-version +integer: 1 + info-hash string, the info hash of the torrent this data is saved for. This is a 20 byte SHA-1 hash of the info section of the diff --git a/3rd/libtorrent-rasterbar/docs/manual-ref.rst b/3rd/libtorrent-rasterbar/docs/manual-ref.rst index b707f7a2..0e996c8d 100644 --- a/3rd/libtorrent-rasterbar/docs/manual-ref.rst +++ b/3rd/libtorrent-rasterbar/docs/manual-ref.rst @@ -473,6 +473,9 @@ The file format is a bencoded dictionary containing the following fields: | ``file-format`` | string: "libtorrent resume file" | | | | +--------------------------+--------------------------------------------------------------+ +| ``file-version`` | integer: 1 | +| | | ++--------------------------+--------------------------------------------------------------+ | ``info-hash`` | string, the info hash of the torrent this data is saved for. | | | This is a 20 byte SHA-1 hash of the info section of the | | | torrent if this is a v1 or v1+v2-hybrid torrent. | diff --git a/3rd/libtorrent-rasterbar/docs/manual.rst b/3rd/libtorrent-rasterbar/docs/manual.rst index bc65cf2c..57531a5d 100644 --- a/3rd/libtorrent-rasterbar/docs/manual.rst +++ b/3rd/libtorrent-rasterbar/docs/manual.rst @@ -471,6 +471,9 @@ The file format is a bencoded dictionary containing the following fields: | ``file-format`` | string: "libtorrent resume file" | | | | +--------------------------+--------------------------------------------------------------+ +| ``file-version`` | integer: 1 | +| | | ++--------------------------+--------------------------------------------------------------+ | ``info-hash`` | string, the info hash of the torrent this data is saved for. | | | This is a 20 byte SHA-1 hash of the info section of the | | | torrent if this is a v1 or v1+v2-hybrid torrent. | diff --git a/3rd/libtorrent-rasterbar/docs/projects.html b/3rd/libtorrent-rasterbar/docs/projects.html index a4784929..39302cb0 100644 --- a/3rd/libtorrent-rasterbar/docs/projects.html +++ b/3rd/libtorrent-rasterbar/docs/projects.html @@ -4,7 +4,7 @@ - + libtorrent diff --git a/3rd/libtorrent-rasterbar/docs/python_binding.html b/3rd/libtorrent-rasterbar/docs/python_binding.html index 351a0cba..1d88fa34 100644 --- a/3rd/libtorrent-rasterbar/docs/python_binding.html +++ b/3rd/libtorrent-rasterbar/docs/python_binding.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,31 +25,31 @@

    libtorrent python binding

    Version: -2.0.8 +2.0.9
    @@ -263,34 +263,34 @@

    Example

    directory.

    A very simple example usage of the module would be something like this:

    -import libtorrent as lt
    -import time
    -import sys
    +import libtorrent as lt
    +import time
    +import sys
     
    -ses = lt.session({'listen_interfaces': '0.0.0.0:6881'})
    +ses = lt.session({'listen_interfaces': '0.0.0.0:6881'})
     
    -info = lt.torrent_info(sys.argv[1])
    -h = ses.add_torrent({'ti': info, 'save_path': '.'})
    -s = h.status()
    -print('starting', s.name)
    +info = lt.torrent_info(sys.argv[1])
    +h = ses.add_torrent({'ti': info, 'save_path': '.'})
    +s = h.status()
    +print('starting', s.name)
     
    -while (not s.is_seeding):
    -    s = h.status()
    +while (not s.is_seeding):
    +    s = h.status()
     
    -    print('\r%.2f%% complete (down: %.1f kB/s up: %.1f kB/s peers: %d) %s' % (
    -        s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000,
    -        s.num_peers, s.state), end=' ')
    +    print('\r%.2f%% complete (down: %.1f kB/s up: %.1f kB/s peers: %d) %s' % (
    +        s.progress * 100, s.download_rate / 1000, s.upload_rate / 1000,
    +        s.num_peers, s.state), end=' ')
     
    -    alerts = ses.pop_alerts()
    -    for a in alerts:
    -        if a.category() & lt.alert.category_t.error_notification:
    -            print(a)
    +    alerts = ses.pop_alerts()
    +    for a in alerts:
    +        if a.category() & lt.alert.category_t.error_notification:
    +            print(a)
     
    -    sys.stdout.flush()
    +    sys.stdout.flush()
     
    -    time.sleep(1)
    +    time.sleep(1)
     
    -print(h.status().name, 'complete')
    +print(h.status().name, 'complete')
     
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Add_Torrent.html b/3rd/libtorrent-rasterbar/docs/reference-Add_Torrent.html index 35a049fa..33132f23 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Add_Torrent.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Add_Torrent.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,19 +25,19 @@ Version: -2.0.8 +2.0.9

    home

    [report issue]
    @@ -55,28 +55,28 @@

    client_data_t

    T* get () const; explicit operator T () const; operator void* () const = delete; - operator void const* () const = delete; client_data_t& operator= (void const*) = delete; + operator void const* () const = delete; client_data_t& operator= (void*) = delete; template <typename T, typename U = typename std::enable_if<std::is_pointer<T>::value>::type> };
-[report issue]
+[report issue]

client_data_t()

 client_data_t () = default;
 

construct a nullptr client data

- -[report issue]
-
-

void*() operator=() const*()

+ +[report issue]
+
+

operator=() void*() const*()

 operator void* () const = delete;
-operator void const* () const = delete;
 client_data_t& operator= (void const*) = delete;
+operator void const* () const = delete;
 client_data_t& operator= (void*) = delete;
 

we don't allow type-unsafe operations

@@ -399,7 +399,9 @@

add_torrent_params

[report issue]
last_download last_upload
the posix time of the last time payload was received or sent for this -torrent, respectively.
+torrent, respectively. A value of 0 means we don't know when we last +uploaded or downloaded, or we have never uploaded or downloaded any +payload for this torrent.
diff --git a/3rd/libtorrent-rasterbar/docs/reference-Alerts.html b/3rd/libtorrent-rasterbar/docs/reference-Alerts.html index 6318d2f6..b41b4dba 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Alerts.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Alerts.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,205 +25,210 @@ Version: -2.0.8 +2.0.9

home

Table of contents

The pop_alerts() function on session is the main interface for retrieving @@ -309,7 +314,7 @@

type()

for (alert* a : alerts) { switch (a->type()) { - case read_piece_alert::alert_type: + case read_piece_alert::alert_type: { auto* p = static_cast<read_piece_alert*>(a); if (p->ec) { @@ -319,7 +324,7 @@

type()

// use p break; } - case file_renamed_alert::alert_type: + case file_renamed_alert::alert_type: { // etc... } @@ -393,7 +398,7 @@

torrent_alert

torrent_handle handle; }; -[report issue]
+[report issue]

message()

 std::string message () const override;
@@ -1490,7 +1495,7 @@ 

server_url()

the URL the error is associated with

[report issue]
-
+

error_message()

 char const* error_message () const;
@@ -1857,7 +1862,7 @@ 

fastresume_rejected_alert

operation_t op; };
-[report issue]
+[report issue]

file_path()

 char const* file_path () const;
@@ -2074,7 +2079,7 @@ 

torrent_error_alert

error_code const error; };
-[report issue]
+[report issue]

filename()

 char const* filename () const;
@@ -2434,7 +2439,7 @@ 

log_alert

static constexpr alert_category_t static_category = alert_category::session_log; };
-[report issue]
+[report issue]

log_message()

 char const* log_message () const;
@@ -2458,7 +2463,7 @@ 

torrent_log_alert

static constexpr alert_category_t static_category = alert_category::torrent_log; };
-[report issue]
+[report issue]

log_message()

 char const* log_message () const;
@@ -2493,14 +2498,14 @@ 

peer_log_alert

direction_t direction; };
-[report issue]
+[report issue]

log_message()

 char const* log_message () const;
 

returns the log message

[report issue]
-
+

enum direction_t

Declared in "libtorrent/alert_types.hpp"

@@ -2721,7 +2726,7 @@

dht_log_alert

dht_module_t module; }; -[report issue]
+[report issue]

log_message()

 char const* log_message () const;
@@ -2805,7 +2810,7 @@ 

pkt_buf()

is valid, which is owned by libtorrent and reclaimed whenever pop_alerts() is called on the session.

[report issue]
-
+

enum direction_t

Declared in "libtorrent/alert_types.hpp"

@@ -2943,19 +2948,19 @@

dht_live_nodes_alert

struct dht_live_nodes_alert final : alert { std::string message () const override; - std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; int num_nodes () const; + std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; static constexpr alert_category_t static_category = alert_category::dht; sha1_hash node_id; }; - -[report issue]
-

nodes() num_nodes()

+ +[report issue]
+

num_nodes() nodes()

-std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const;
 int num_nodes () const;
+std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const;
 

the number of nodes in the routing table and the actual nodes.

[report issue]
@@ -2992,8 +2997,8 @@

dht_sample_infohashes_alert

struct dht_sample_infohashes_alert final : alert { std::string message () const override; - int num_samples () const; std::vector<sha1_hash> samples () const; + int num_samples () const; int num_nodes () const; std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; @@ -3008,8 +3013,8 @@

dht_sample_infohashes_alert

[report issue]

num_samples() samples()

-int num_samples () const;
 std::vector<sha1_hash> samples () const;
+int num_samples () const;
 

returns the number of info-hashes returned by the node, as well as the actual info-hashes. num_samples() is more efficient than @@ -3198,6 +3203,101 @@

torrent_conflict_alert

One way to resolve the conflict is to remove both failing torrents and re-add it using this metadata
+[report issue]
+
+

peer_info_alert

+

Declared in "libtorrent/alert_types.hpp"

+

posted when torrent_handle::post_peer_info() is called

+
+struct peer_info_alert final : torrent_alert
+{
+   std::string message () const override;
+
+   static constexpr alert_category_t static_category  = alert_category::status;
+   std::vector<lt::peer_info> peer_info;
+};
+
+[report issue]
+
peer_info
+
the list of the currently connected peers
+
+[report issue]
+
+

file_progress_alert

+

Declared in "libtorrent/alert_types.hpp"

+

posted when torrent_handle::post_file_progress() is called

+
+struct file_progress_alert final : torrent_alert
+{
+   std::string message () const override;
+
+   static constexpr alert_category_t static_category  = alert_category::file_progress;
+   aux::vector<std::int64_t, file_index_t> files;
+};
+
+[report issue]
+
files
+
the list of the files in the torrent
+
+[report issue]
+
+

piece_info_alert

+

Declared in "libtorrent/alert_types.hpp"

+

posted when torrent_handle::post_download_queue() is called

+
+struct piece_info_alert final : torrent_alert
+{
+   std::string message () const override;
+
+   static constexpr alert_category_t static_category  = alert_category::piece_progress;
+   std::vector<partial_piece_info> piece_info;
+   std::vector<block_info> block_data;
+};
+
+[report issue]
+
piece_info
+
info about pieces being downloaded for the torrent
+
+[report issue]
+
block_data
+
storage for block_info pointers in partial_piece_info objects
+
+[report issue]
+
+

piece_availability_alert

+

Declared in "libtorrent/alert_types.hpp"

+

posted when torrent_handle::post_piece_availability() is called

+
+struct piece_availability_alert final : torrent_alert
+{
+   std::string message () const override;
+
+   static constexpr alert_category_t static_category  = alert_category::status;
+   std::vector<int> piece_availability;
+};
+
+[report issue]
+
piece_availability
+
info about pieces being downloaded for the torrent
+
+[report issue]
+
+

tracker_list_alert

+

Declared in "libtorrent/alert_types.hpp"

+

posted when torrent_handle::post_trackers() is called

+
+struct tracker_list_alert final : torrent_alert
+{
+   std::string message () const override;
+
+   static constexpr alert_category_t static_category  = alert_category::status;
+   std::vector<announce_entry> trackers;
+};
+
+[report issue]
+
trackers
+
list of trackers and their status for the torrent
+
[report issue]

alert_cast()

diff --git a/3rd/libtorrent-rasterbar/docs/reference-Bdecoding.html b/3rd/libtorrent-rasterbar/docs/reference-Bdecoding.html index e137778d..bab62841 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Bdecoding.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Bdecoding.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,34 +25,34 @@
- +
Version:2.0.8
2.0.9

home

[report issue]
@@ -66,38 +66,38 @@

bdecode_node

struct bdecode_node { bdecode_node () = default; - bdecode_node& operator= (bdecode_node const&) &; - bdecode_node (bdecode_node&&) noexcept; bdecode_node& operator= (bdecode_node&&) & = default; + bdecode_node (bdecode_node&&) noexcept; + bdecode_node& operator= (bdecode_node const&) &; bdecode_node (bdecode_node const&); type_t type () const noexcept; explicit operator bool () const noexcept; bdecode_node non_owning () const; - std::ptrdiff_t data_offset () const noexcept; span<char const> data_section () const noexcept; - int list_size () const; + std::ptrdiff_t data_offset () const noexcept; + bdecode_node list_at (int i) const; string_view list_string_value_at (int i , string_view default_val = string_view()) const; + int list_size () const; std::int64_t list_int_value_at (int i , std::int64_t default_val = 0) const; - bdecode_node list_at (int i) const; - std::pair<string_view, bdecode_node> dict_at (int i) const; - std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const; - bdecode_node dict_find_string (string_view key) const; - bdecode_node dict_find_int (string_view key) const; - string_view dict_find_string_value (string_view key - , string_view default_value = string_view()) const; + bdecode_node dict_find_dict (string_view key) const; std::int64_t dict_find_int_value (string_view key , std::int64_t default_val = 0) const; + bdecode_node dict_find_list (string_view key) const; + std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const; + bdecode_node dict_find_int (string_view key) const; int dict_size () const; - bdecode_node dict_find_dict (string_view key) const; + std::pair<string_view, bdecode_node> dict_at (int i) const; bdecode_node dict_find (string_view key) const; - bdecode_node dict_find_list (string_view key) const; + bdecode_node dict_find_string (string_view key) const; + string_view dict_find_string_value (string_view key + , string_view default_value = string_view()) const; std::int64_t int_value () const; + int string_length () const; std::ptrdiff_t string_offset () const; char const* string_ptr () const; string_view string_value () const; - int string_length () const; void clear (); void swap (bdecode_node& n); void reserve (int tokens); @@ -114,20 +114,20 @@

bdecode_node

}; }; -[report issue]
+[report issue]

bdecode_node()

 bdecode_node () = default;
 

creates a default constructed node, it will have the type none_t.

- -[report issue]
-
-

operator=() bdecode_node()

+ +[report issue]
+
+

bdecode_node() operator=()

-bdecode_node& operator= (bdecode_node const&) &;
-bdecode_node (bdecode_node&&) noexcept;
 bdecode_node& operator= (bdecode_node&&) & = default;
+bdecode_node (bdecode_node&&) noexcept;
+bdecode_node& operator= (bdecode_node const&) &;
 bdecode_node (bdecode_node const&);
 

For owning nodes, the copy will create a copy of the tree, but the @@ -159,8 +159,8 @@

non_owning()

data_offset() data_section()

-std::ptrdiff_t data_offset () const noexcept;
 span<char const> data_section () const noexcept;
+std::ptrdiff_t data_offset () const noexcept;
 

returns the buffer and length of the section in the original bencoded buffer where this node is defined. For a dictionary for instance, this @@ -168,49 +168,49 @@

data_offset() data_section()

dictionary in between. the data_offset() function returns the byte-offset to this node in, starting from the beginning of the buffer that was parsed.

- - -[report issue]
-
-

list_at() list_string_value_at() list_size() list_int_value_at()

+ + +[report issue]
+
+

list_size() list_string_value_at() list_int_value_at() list_at()

-int list_size () const;
+bdecode_node list_at (int i) const;
 string_view list_string_value_at (int i
       , string_view default_val = string_view()) const;
+int list_size () const;
 std::int64_t list_int_value_at (int i
       , std::int64_t default_val = 0) const;
-bdecode_node list_at (int i) const;
 

functions with the list_ prefix operate on lists. These functions are only valid if type() == list_t. list_at() returns the item in the list at index i. i may not be greater than or equal to the size of the list. size() returns the size of the list.

- - - - - + + + -[report issue]
-
-

dict_find_int_value() dict_at() dict_find() dict_find_dict() dict_size() dict_find_int() dict_at_node() dict_find_string_value() dict_find_string() dict_find_list()

+ + +[report issue]
+
+

dict_find_dict() dict_at_node() dict_at() dict_find() dict_find_string_value() dict_find_list() dict_find_string() dict_find_int() dict_size() dict_find_int_value()

-std::pair<string_view, bdecode_node> dict_at (int i) const;
-std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const;
-bdecode_node dict_find_string (string_view key) const;
-bdecode_node dict_find_int (string_view key) const;
-string_view dict_find_string_value (string_view key
-      , string_view default_value = string_view()) const;
+bdecode_node dict_find_dict (string_view key) const;
 std::int64_t dict_find_int_value (string_view key
       , std::int64_t default_val = 0) const;
+bdecode_node dict_find_list (string_view key) const;
+std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const;
+bdecode_node dict_find_int (string_view key) const;
 int dict_size () const;
-bdecode_node dict_find_dict (string_view key) const;
+std::pair<string_view, bdecode_node> dict_at (int i) const;
 bdecode_node dict_find (string_view key) const;
-bdecode_node dict_find_list (string_view key) const;
+bdecode_node dict_find_string (string_view key) const;
+string_view dict_find_string_value (string_view key
+      , string_view default_value = string_view()) const;
 

Functions with the dict_ prefix operates on dictionaries. They are only valid if type() == dict_t. In case a key you're looking up @@ -235,15 +235,15 @@

int_value()

value of the integer.

- -[report issue]
-
-

string_offset() string_ptr() string_length() string_value()

+ +[report issue]
+
+

string_offset() string_ptr() string_value() string_length()

+int string_length () const;
 std::ptrdiff_t string_offset () const;
 char const* string_ptr () const;
 string_view string_value () const;
-int string_length () const;
 

these functions are only valid if type() == string_t. They return the string values. Note that string_ptr() is not 0-terminated. @@ -349,12 +349,12 @@

print_entry()

bdecode()

Declared in "libtorrent/bdecode.hpp"

-int bdecode (char const* start, char const* end, bdecode_node& ret
+bdecode_node bdecode (span<char const> buffer
    , error_code& ec, int* error_pos = nullptr, int depth_limit = 100
    , int token_limit = 2000000);
 bdecode_node bdecode (span<char const> buffer
    , int depth_limit = 100, int token_limit = 2000000);
-bdecode_node bdecode (span<char const> buffer
+int bdecode (char const* start, char const* end, bdecode_node& ret
    , error_code& ec, int* error_pos = nullptr, int depth_limit = 100
    , int token_limit = 2000000);
 
diff --git a/3rd/libtorrent-rasterbar/docs/reference-Bencoding.html b/3rd/libtorrent-rasterbar/docs/reference-Bencoding.html index 9efa104f..d5401986 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Bencoding.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Bencoding.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,29 +25,29 @@ Version: -2.0.8 +2.0.9

home

Bencoding is a common representation in bittorrent used for dictionary, @@ -74,37 +74,37 @@

entry

{ data_type type () const; entry (preformatted_type); + entry (dictionary_type); entry (list_type); entry (span<char const>); entry (integer_type); - entry (dictionary_type); entry (U v); entry (data_type t); entry (bdecode_node const& n); - entry& operator= (span<char const>) &; - entry& operator= (preformatted_type) &; entry& operator= (bdecode_node const&) &; + entry& operator= (preformatted_type) &; + entry& operator= (span<char const>) &; + entry& operator= (entry const&) &; entry& operator= (list_type) &; - entry& operator= (integer_type) &; - entry& operator= (dictionary_type) &; entry& operator= (entry&&) & noexcept; - entry& operator= (entry const&) &; + entry& operator= (dictionary_type) &; + entry& operator= (integer_type) &; entry& operator= (U v) &; list_type const& list () const; - preformatted_type& preformatted (); - dictionary_type& dict (); - dictionary_type const& dict () const; + preformatted_type const& preformatted () const; list_type& list (); - string_type const& string () const; + preformatted_type& preformatted (); integer_type const& integer () const; - string_type& string (); + string_type const& string () const; + dictionary_type& dict (); integer_type& integer (); - preformatted_type const& preformatted () const; + string_type& string (); + dictionary_type const& dict () const; void swap (entry& e); - entry& operator[] (string_view key); entry const& operator[] (string_view key) const; - entry const* find_key (string_view key) const; + entry& operator[] (string_view key); entry* find_key (string_view key); + entry const* find_key (string_view key) const; std::string to_string (bool single_line = false) const; enum data_type @@ -125,20 +125,20 @@

type()

returns the concrete type of the entry

[report issue]
-
+

entry()

 entry (preformatted_type);
+entry (dictionary_type);
 entry (list_type);
 entry (span<char const>);
 entry (integer_type);
-entry (dictionary_type);
 

constructors directly from a specific type. The content of the argument is copied into the newly constructed entry

[report issue]
-
+

entry()

 entry (data_type t);
@@ -146,7 +146,7 @@ 

entry()

construct an empty entry of the specified type. see data_type enum.

[report issue]
-
+

entry()

 entry (bdecode_node const& n);
@@ -156,35 +156,35 @@ 

entry()

operator=()

-entry& operator= (span<char const>) &;
-entry& operator= (preformatted_type) &;
 entry& operator= (bdecode_node const&) &;
+entry& operator= (preformatted_type) &;
+entry& operator= (span<char const>) &;
+entry& operator= (entry const&) &;
 entry& operator= (list_type) &;
-entry& operator= (integer_type) &;
-entry& operator= (dictionary_type) &;
 entry& operator= (entry&&) & noexcept;
-entry& operator= (entry const&) &;
+entry& operator= (dictionary_type) &;
+entry& operator= (integer_type) &;
 

copies the structure of the right hand side into this entry.

- + -[report issue]
-
-

list() string() dict() integer() preformatted()

+[report issue]
+
+

string() list() dict() integer() preformatted()

 list_type const& list () const;
-preformatted_type& preformatted ();
-dictionary_type& dict ();
-dictionary_type const& dict () const;
+preformatted_type const& preformatted () const;
 list_type& list ();
-string_type const& string () const;
+preformatted_type& preformatted ();
 integer_type const& integer () const;
-string_type& string ();
+string_type const& string () const;
+dictionary_type& dict ();
 integer_type& integer ();
-preformatted_type const& preformatted () const;
+string_type& string ();
+dictionary_type const& dict () const;
 

The integer(), string(), list() and dict() functions are accessors that return the respective type. If the entry object @@ -233,11 +233,11 @@

swap()

swaps the content of this with e.

[report issue]
-
+

operator[]()

-entry& operator[] (string_view key);
 entry const& operator[] (string_view key) const;
+entry& operator[] (string_view key);
 

All of these functions requires the entry to be a dictionary, if it isn't they will throw system_error.

@@ -252,8 +252,8 @@

operator[]()

find_key()

-entry const* find_key (string_view key) const;
 entry* find_key (string_view key);
+entry const* find_key (string_view key) const;
 

These functions requires the entry to be a dictionary, if it isn't they will throw system_error.

@@ -313,7 +313,7 @@

enum data_type

[report issue]
-
+

operator<<()

Declared in "libtorrent/entry.hpp"

@@ -337,7 +337,7 @@ 

bencode()

function assumes the value_type of the iterator is a char. In order to encode entry e into a buffer, do:

-std::vector<char> buffer;
+std::vector<char> buf;
 bencode(std::back_inserter(buf), e);
 
diff --git a/3rd/libtorrent-rasterbar/docs/reference-Core.html b/3rd/libtorrent-rasterbar/docs/reference-Core.html index 23a14ff7..bc661d0a 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Core.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Core.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,44 +25,48 @@ Version: -2.0.8 +2.0.9

home

[report issue]
@@ -114,10 +118,10 @@

info_hash_t

 struct info_hash_t
 {
-   info_hash_t (sha1_hash h1, sha256_hash h2) noexcept;
-   explicit info_hash_t (sha256_hash h2) noexcept;
    info_hash_t () noexcept = default;
+   info_hash_t (sha1_hash h1, sha256_hash h2) noexcept;
    explicit info_hash_t (sha1_hash h1) noexcept;
+   explicit info_hash_t (sha256_hash h2) noexcept;
    bool has_v2 () const;
    bool has (protocol_version v) const;
    bool has_v1 () const;
@@ -133,24 +137,24 @@ 

info_hash_t

sha256_hash v2; };
-[report issue]
+[report issue]

info_hash_t()

-info_hash_t (sha1_hash h1, sha256_hash h2) noexcept;
-explicit info_hash_t (sha256_hash h2) noexcept;
 info_hash_t () noexcept = default;
+info_hash_t (sha1_hash h1, sha256_hash h2) noexcept;
 explicit info_hash_t (sha1_hash h1) noexcept;
+explicit info_hash_t (sha256_hash h2) noexcept;
 

The default constructor creates an object that has neither a v1 or v2 hash.

For backwards compatibility, make it possible to construct directly from a v1 hash. This constructor allows implicit conversion from a v1 hash, but the implicitness is deprecated.

- + -[report issue]
-
-

has() has_v1() has_v2()

+[report issue]
+
+

has_v2() has_v1() has()

 bool has_v2 () const;
 bool has (protocol_version v) const;
@@ -194,6 +198,8 @@ 

peer_info

 struct peer_info
 {
+   sha256_hash i2p_destination () const;
+
    std::string client;
    typed_bitfield<piece_index_t> pieces;
    std::int64_t total_download;
@@ -278,6 +284,13 @@ 

peer_info

bandwidth_state_flags_t write_state; };
+[report issue]
+

i2p_destination()

+
+sha256_hash i2p_destination () const;
+
+

If this peer is an i2p peer, this function returns the destination +address of the peer

[report issue]
client
A human readable string describing the software at the other end of @@ -474,7 +487,7 @@

peer_info

[report issue]
pid
-
the peer's id as used in the bit torrent protocol. This id can be used +
the peer's id as used in the bittorrent protocol. This id can be used to extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer is using. See identify_client()_
@@ -623,13 +636,15 @@

peer_info

[report issue]
ip
the IP-address to this peer. The type is an asio endpoint. For -more info, see the asio documentation.
+more info, see the asio documentation. This field is not valid for +i2p peers. Instead use the i2p_destination() function.
[report issue]
local_endpoint
the IP and port pair the socket is bound to locally. i.e. the IP address of the interface it's going out over. This may be useful for -multi-homed clients with multiple interfaces to the internet.
+multi-homed clients with multiple interfaces to the internet. +This field is not valid for i2p peers.
[report issue]
bw_idle
@@ -661,6 +676,7 @@

peer_info

class.
[report issue]
+

piece_block

Declared in "libtorrent/piece_block.hpp"

@@ -688,24 +704,24 @@

version()

returns the libtorrent version as string form in this format: "<major>.<minor>.<tiny>.<tag>"

- -[report issue]
-
-

load_torrent_parsed() load_torrent_file() load_torrent_buffer()

+ +[report issue]
+
+

load_torrent_parsed() load_torrent_buffer() load_torrent_file()

Declared in "libtorrent/load_torrent.hpp"

-add_torrent_params load_torrent_parsed (
-   bdecode_node const& torrent_file, load_torrent_limits const& cfg);
-add_torrent_params load_torrent_file (
-   std::string const& filename);
 add_torrent_params load_torrent_buffer (
    span<char const> buffer);
-add_torrent_params load_torrent_parsed (
-   bdecode_node const& torrent_file);
 add_torrent_params load_torrent_buffer (
    span<char const> buffer, load_torrent_limits const& cfg);
 add_torrent_params load_torrent_file (
    std::string const& filename, load_torrent_limits const& cfg);
+add_torrent_params load_torrent_file (
+   std::string const& filename);
+add_torrent_params load_torrent_parsed (
+   bdecode_node const& torrent_file);
+add_torrent_params load_torrent_parsed (
+   bdecode_node const& torrent_file, load_torrent_limits const& cfg);
 

These functions load the content of a .torrent file into an add_torrent_params object. @@ -720,6 +736,13 @@

load_torrent_parsed() load_torrent_file() load_torrent_buffer()

  • turned into a magnet link via make_magnet_uri()
  • +[report issue]
    +
    +

    torrent_peer_equal()

    +

    Declared in "libtorrent/torrent_peer.hpp"

    +
    +inline bool torrent_peer_equal (torrent_peer const* lhs, torrent_peer const* rhs);
    +
    [report issue]

    truncate_files()

    @@ -734,9 +757,9 @@

    truncate_files()

    make_magnet_uri()

    Declared in "libtorrent/magnet_uri.hpp"

    -std::string make_magnet_uri (torrent_info const& info);
     std::string make_magnet_uri (torrent_handle const& handle);
     std::string make_magnet_uri (add_torrent_params const& atp);
    +std::string make_magnet_uri (torrent_info const& info);
     

    Generates a magnet URI from the specified torrent.

    Several fields from the add_torrent_params objects are recorded in the @@ -765,8 +788,8 @@

    parse_magnet_uri()

    Declared in "libtorrent/magnet_uri.hpp"

     void parse_magnet_uri (string_view uri, add_torrent_params& p, error_code& ec);
    -add_torrent_params parse_magnet_uri (string_view uri);
     add_torrent_params parse_magnet_uri (string_view uri, error_code& ec);
    +add_torrent_params parse_magnet_uri (string_view uri);
     

    This function parses out information from the magnet link and populates the add_torrent_params object. The overload that does not take an @@ -1240,12 +1263,14 @@

    torrent_flags_t

    need_save_resume
    -
    if this flag is set (which it is by default) the torrent will be -considered needing to save its resume data immediately as it's -added. New torrents that don't have any resume data should do that. -This flag is cleared by a successful call to save_resume_data() +

    if this flag is set (which it is by default) the torrent will be +considered needing to save its resume data immediately, in the +category if_metadata_changed. See resume_data_flags_t and +save_resume_data() for details.

    +

    This flag is cleared by a successful call to save_resume_data() This flag is not saved by write_resume_data(), since it represents an -ephemeral state of a running torrent.

    +ephemeral state of a running torrent.

    +
    disable_dht
    @@ -1281,6 +1306,19 @@

    torrent_flags_t

    unless this flag is set, in which case they will be set to 0 (dont_download).
    +
    +
    i2p_torrent
    +
    this flag makes the torrent be considered an "i2p torrent" for purposes +of the allow_i2p_mixed setting. When mixing regular peers and i2p peers +is disabled, i2p torrents won't add normal peers to its peer list. +Note that non i2p torrents may still allow i2p peers (on the off-chance +that a tracker return them and the session is configured with a SAM +connection). +This flag is set automatically when adding a torrent that has at least +one tracker whose hostname ends with .i2p. +It's also set by parse_magnet_uri() if the tracker list contains such +URL.
    +
    all
    all torrent flags combined. Can conveniently be used when creating masks diff --git a/3rd/libtorrent-rasterbar/docs/reference-Create_Torrents.html b/3rd/libtorrent-rasterbar/docs/reference-Create_Torrents.html index 70ef517e..dcfe8835 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Create_Torrents.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Create_Torrents.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,38 +25,38 @@ Version: -2.0.8 +2.0.9

    home

    This section describes the functions and classes that are used @@ -91,7 +91,7 @@ // reads the files and calculates the hashes set_piece_hashes(t, "."); -ofstream out("my_torrent.torrent", std::ios_base::binary); +ofstream out("my_torrent.torrent", std::ios_base::binary); std::vector<char> buf = t.generate_buf(); out.write(buf.data(), buf.size()); @@ -109,9 +109,9 @@

    create_torrent

     struct create_torrent
     {
    -   explicit create_torrent (torrent_info const& ti);
        explicit create_torrent (file_storage& fs, int piece_size = 0
           , create_flags_t flags = {});
    +   explicit create_torrent (torrent_info const& ti);
        entry generate () const;
        std::vector<char> generate_buf () const;
        file_storage const& files () const;
    @@ -120,8 +120,8 @@ 

    create_torrent

    void set_creation_date (std::time_t timestamp); void set_hash (piece_index_t index, sha1_hash const& h); void set_hash2 (file_index_t file, piece_index_t::diff_type piece, sha256_hash const& h); - void add_http_seed (string_view url); void add_url_seed (string_view url); + void add_http_seed (string_view url); void add_node (std::pair<std::string, int> node); void add_tracker (string_view url, int tier = 0); void set_root_cert (string_view cert); @@ -150,12 +150,12 @@

    create_torrent

    static constexpr create_flags_t canonical_files_no_tail_padding = 9_bit; };
    -[report issue]
    +[report issue]

    create_torrent()

    -explicit create_torrent (torrent_info const& ti);
     explicit create_torrent (file_storage& fs, int piece_size = 0
           , create_flags_t flags = {});
    +explicit create_torrent (torrent_info const& ti);
     

    The piece_size is the size of each piece in bytes. It must be a power of 2 and a minimum of 16 kiB. If a piece size of 0 is @@ -274,13 +274,13 @@

    set_hash2()

    when calling generate(). This function will throw std::system_error if it is called on an object constructed with the v1_only flag.

    - -[report issue]
    -
    -

    add_http_seed() add_url_seed()

    + +[report issue]
    +
    +

    add_url_seed() add_http_seed()

    -void add_http_seed (string_view url);
     void add_url_seed (string_view url);
    +void add_http_seed (string_view url);
     

    This adds a url seed to the torrent. You can have any number of url seeds. For a single file torrent, this should be an HTTP url, pointing to a file with identical @@ -382,10 +382,10 @@

    piece_size() piece_length()

    piece_length() returns the piece size of all pieces but the last one. piece_size() returns the size of the specified piece. these functions are just forwarding to the associated file_storage.

    - -[report issue]
    -
    -

    add_similar_torrent() add_collection()

    + +[report issue]
    +
    +

    add_collection() add_similar_torrent()

     void add_similar_torrent (sha1_hash ih);
     void add_collection (string_view c);
    @@ -485,20 +485,20 @@ 

    set_piece_hashes()

    Declared in "libtorrent/create_torrent.hpp"

     inline void set_piece_hashes (create_torrent& t, std::string const& p);
    -void set_piece_hashes (create_torrent& t, std::string const& p
    -   , settings_interface const& settings, disk_io_constructor_type disk_io
    -   , std::function<void(piece_index_t)> const& f, error_code& ec);
     inline void set_piece_hashes (create_torrent& t, std::string const& p
    +   , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f);
     void set_piece_hashes (create_torrent& t, std::string const& p
        , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f, error_code& ec);
     void set_piece_hashes (create_torrent& t, std::string const& p
        , std::function<void(piece_index_t)> const& f, error_code& ec);
    -inline void set_piece_hashes (create_torrent& t, std::string const& p, error_code& ec);
    +void set_piece_hashes (create_torrent& t, std::string const& p
    +   , settings_interface const& settings, disk_io_constructor_type disk_io
    +   , std::function<void(piece_index_t)> const& f, error_code& ec);
     inline void set_piece_hashes (create_torrent& t, std::string const& p
    -   , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f);
    +inline void set_piece_hashes (create_torrent& t, std::string const& p, error_code& ec);
     

    This function will assume that the files added to the torrent file exists at path p, read those files and hash the content and set the hashes in the create_torrent diff --git a/3rd/libtorrent-rasterbar/docs/reference-Custom_Storage.html b/3rd/libtorrent-rasterbar/docs/reference-Custom_Storage.html index 22ef9c6a..cece390f 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Custom_Storage.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Custom_Storage.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,54 +25,54 @@ Version: -2.0.8 +2.0.9

    home

    The disk I/O can be customized in libtorrent. In previous versions, the @@ -352,13 +352,13 @@

    settings_interface

     struct settings_interface
     {
    -   virtual void set_int (int name, int val) = 0;
    +   virtual void set_str (int name, std::string val) = 0;
        virtual void set_bool (int name, bool val) = 0;
    +   virtual void set_int (int name, int val) = 0;
        virtual bool has_val (int name) const = 0;
    -   virtual void set_str (int name, std::string val) = 0;
    -   virtual std::string const& get_str (int name) const = 0;
    -   virtual bool get_bool (int name) const = 0;
        virtual int get_int (int name) const = 0;
    +   virtual bool get_bool (int name) const = 0;
    +   virtual std::string const& get_str (int name) const = 0;
     };
     
    [report issue]
    @@ -432,13 +432,13 @@

    disk_interface

    virtual storage_holder new_torrent (storage_params const& p , std::shared_ptr<void> const& torrent) = 0; virtual void remove_torrent (storage_index_t) = 0; + virtual void async_read (storage_index_t storage, peer_request const& r + , std::function<void(disk_buffer_holder, storage_error const&)> handler + , disk_job_flags_t flags = {}) = 0; virtual bool async_write (storage_index_t storage, peer_request const& r , char const* buf, std::shared_ptr<disk_observer> o , std::function<void(storage_error const&)> handler , disk_job_flags_t flags = {}) = 0; - virtual void async_read (storage_index_t storage, peer_request const& r - , std::function<void(disk_buffer_holder, storage_error const&)> handler - , disk_job_flags_t flags = {}) = 0; virtual void async_hash (storage_index_t storage, piece_index_t piece, span<sha256_hash> v2 , disk_job_flags_t flags , std::function<void(piece_index_t, sha1_hash const&, storage_error const&)> handler) = 0; @@ -498,18 +498,18 @@

    remove_torrent()

    remove the storage with the specified index. This is not expected to delete any files from disk, just to clean up any resources associated with the specified storage.

    - -[report issue]
    -
    -

    async_write() async_read()

    + +[report issue]
    +
    +

    async_read() async_write()

    +virtual void async_read (storage_index_t storage, peer_request const& r
    +      , std::function<void(disk_buffer_holder, storage_error const&)> handler
    +      , disk_job_flags_t flags = {}) = 0;
     virtual bool async_write (storage_index_t storage, peer_request const& r
           , char const* buf, std::shared_ptr<disk_observer> o
           , std::function<void(storage_error const&)> handler
           , disk_job_flags_t flags = {}) = 0;
    -virtual void async_read (storage_index_t storage, peer_request const& r
    -      , std::function<void(disk_buffer_holder, storage_error const&)> handler
    -      , disk_job_flags_t flags = {}) = 0;
     

    perform a read or write operation from/to the specified storage index and the specified request. When the operation completes, call @@ -768,14 +768,14 @@

    storage_holder

     struct storage_holder
     {
    -   ~storage_holder ();
        storage_holder (storage_index_t idx, disk_interface& disk_io);
    +   ~storage_holder ();
        storage_holder () = default;
        explicit operator bool () const;
        operator storage_index_t () const;
        void reset ();
    -   storage_holder& operator= (storage_holder const&) = delete;
        storage_holder (storage_holder const&) = delete;
    +   storage_holder& operator= (storage_holder const&) = delete;
        storage_holder (storage_holder&& rhs) noexcept;
        storage_holder& operator= (storage_holder&& rhs) noexcept;
     };
    @@ -804,10 +804,10 @@ 

    disk_buffer_holder

     struct disk_buffer_holder
     {
    -   disk_buffer_holder& operator= (disk_buffer_holder&&) & noexcept;
        disk_buffer_holder (disk_buffer_holder&&) noexcept;
    -   disk_buffer_holder& operator= (disk_buffer_holder const&) = delete;
    +   disk_buffer_holder& operator= (disk_buffer_holder&&) & noexcept;
        disk_buffer_holder (disk_buffer_holder const&) = delete;
    +   disk_buffer_holder& operator= (disk_buffer_holder const&) = delete;
        disk_buffer_holder (buffer_allocator_interface& alloc
           , char* buf, int sz) noexcept;
        disk_buffer_holder () noexcept = default;
    @@ -820,7 +820,7 @@ 

    disk_buffer_holder

    std::ptrdiff_t size () const; };
    -[report issue]
    +[report issue]

    disk_buffer_holder()

     disk_buffer_holder (buffer_allocator_interface& alloc
    @@ -830,14 +830,14 @@ 

    disk_buffer_holder()

    using a disk buffer pool directly (there's only one disk_buffer_pool per session)

    [report issue]
    -
    +

    disk_buffer_holder()

     disk_buffer_holder () noexcept = default;
     

    default construct a holder that does not own any buffer

    [report issue]
    -
    +

    ~disk_buffer_holder()

     ~disk_buffer_holder ();
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-DHT.html b/3rd/libtorrent-rasterbar/docs/reference-DHT.html
    index c857c7df..2d8a56bf 100644
    --- a/3rd/libtorrent-rasterbar/docs/reference-DHT.html
    +++ b/3rd/libtorrent-rasterbar/docs/reference-DHT.html
    @@ -4,7 +4,7 @@
     
     
     
    -
    +
     libtorrent
     
     
    @@ -25,35 +25,35 @@
     
     
     Version:
    -2.0.8
    +2.0.9
     
     
     

    home

    [report issue]
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Error_Codes.html b/3rd/libtorrent-rasterbar/docs/reference-Error_Codes.html index bd66f81a..26972aa3 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Error_Codes.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Error_Codes.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,34 +25,34 @@ Version: -2.0.8 +2.0.9

    home

    [report issue]
    @@ -310,7 +310,7 @@

    enum i2p_error_code

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/bdecode.hpp"

    @@ -365,7 +365,7 @@

    enum error_code_enum

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/upnp.hpp"

    @@ -434,7 +434,7 @@

    enum error_code_enum

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/error_code.hpp"

    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Filter.html b/3rd/libtorrent-rasterbar/docs/reference-Filter.html index 6b0be3f1..8460338e 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Filter.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Filter.html @@ -4,7 +4,7 @@ - +libtorrent @@ -25,25 +25,25 @@ - +
    Version:2.0.8
    2.0.9

    home

    Table of contents

    -
    -

    on_piece_pass() on_piece_failed()

    + +[report issue]
    +
    +

    on_piece_failed() on_piece_pass()

     virtual void on_piece_failed (piece_index_t);
     virtual void on_piece_pass (piece_index_t);
    @@ -464,13 +464,13 @@ 

    tick()

    This hook is called approximately once per second. It is a way of making it easy for plugins to do timed events, for sending messages or whatever.

    - -[report issue]
    -
    -

    on_pause() on_resume()

    + +[report issue]
    +
    +

    on_resume() on_pause()

    -virtual bool on_pause ();
     virtual bool on_resume ();
    +virtual bool on_pause ();
     

    These hooks are called when the torrent is paused and resumed respectively. The return value indicates if the event was handled. A return value of @@ -543,35 +543,35 @@

    peer_plugin

    virtual void on_connected (); virtual bool on_handshake (span<char const>); virtual bool on_extension_handshake (bdecode_node const&); - virtual bool on_choke (); - virtual bool on_bitfield (bitfield const& /*bitfield*/); - virtual bool on_have_all (); + virtual bool on_request (peer_request const&); + virtual bool on_unchoke (); virtual bool on_have (piece_index_t); + virtual bool on_not_interested (); + virtual bool on_choke (); virtual bool on_dont_have (piece_index_t); + virtual bool on_have_all (); virtual bool on_allowed_fast (piece_index_t); - virtual bool on_not_interested (); - virtual bool on_request (peer_request const&); - virtual bool on_interested (); virtual bool on_have_none (); - virtual bool on_unchoke (); + virtual bool on_interested (); + virtual bool on_bitfield (bitfield const& /*bitfield*/); virtual bool on_piece (peer_request const& /*piece*/ , span<char const> /*buf*/); + virtual bool on_reject (peer_request const&); virtual bool on_cancel (peer_request const&); virtual bool on_suggest (piece_index_t); - virtual bool on_reject (peer_request const&); - virtual void sent_choke (); - virtual void sent_request (peer_request const&); virtual void sent_cancel (peer_request const&); - virtual void sent_allow_fast (piece_index_t); virtual void sent_suggest (piece_index_t); + virtual void sent_choke (); + virtual void sent_allow_fast (piece_index_t); + virtual void sent_have_none (); + virtual void sent_request (peer_request const&); virtual void sent_reject_request (peer_request const&); virtual void sent_have_all (); - virtual void sent_have_none (); virtual void sent_piece (peer_request const&); - virtual void sent_have (piece_index_t); virtual void sent_unchoke (); - virtual void sent_interested (); virtual void sent_not_interested (); + virtual void sent_have (piece_index_t); + virtual void sent_interested (); virtual void sent_payload (int /* bytes */); virtual bool can_disconnect (error_code const& /*ec*/); virtual bool on_extended (int /*length*/, int /*msg*/, @@ -637,31 +637,31 @@

    on_extension_handshake()

    supported by this peer. It will result in this peer_plugin being removed from the peer_connection and destructed. this is not called for web seeds

    - - - - + - - + - + + + -[report issue]
    -
    -

    on_bitfield() on_dont_have() on_allowed_fast() on_choke() on_have() on_unchoke() on_have_all() on_request() on_not_interested() on_interested() on_have_none()

    + + +[report issue]
    +
    +

    on_have_none() on_have() on_allowed_fast() on_request() on_have_all() on_bitfield() on_unchoke() on_interested() on_dont_have() on_not_interested() on_choke()

    -virtual bool on_choke ();
    -virtual bool on_bitfield (bitfield const& /*bitfield*/);
    -virtual bool on_have_all ();
    +virtual bool on_request (peer_request const&);
    +virtual bool on_unchoke ();
     virtual bool on_have (piece_index_t);
    +virtual bool on_not_interested ();
    +virtual bool on_choke ();
     virtual bool on_dont_have (piece_index_t);
    +virtual bool on_have_all ();
     virtual bool on_allowed_fast (piece_index_t);
    -virtual bool on_not_interested ();
    -virtual bool on_request (peer_request const&);
    -virtual bool on_interested ();
     virtual bool on_have_none ();
    -virtual bool on_unchoke ();
    +virtual bool on_interested ();
    +virtual bool on_bitfield (bitfield const& /*bitfield*/);
     

    returning true from any of the message handlers indicates that the plugin has handled the message. @@ -681,19 +681,19 @@

    on_piece()

    in the length member of the piece parameter. returns true to indicate that the piece is handled and the rest of the logic should be ignored.

    - - -[report issue]
    -
    -

    sent_have() sent_not_interested() sent_interested() sent_unchoke() sent_piece()

    + + +[report issue]
    +
    +

    sent_not_interested() sent_interested() sent_have() sent_piece() sent_unchoke()

     virtual void sent_piece (peer_request const&);
    -virtual void sent_have (piece_index_t);
     virtual void sent_unchoke ();
    -virtual void sent_interested ();
     virtual void sent_not_interested ();
    +virtual void sent_have (piece_index_t);
    +virtual void sent_interested ();
     

    called after a choke message has been sent to the peer

    [report issue]
    @@ -737,10 +737,10 @@

    on_unknown_message()

    span<char const> /*body*/);

    this is not called for web seeds

    - -[report issue]
    -
    -

    on_piece_pass() on_piece_failed()

    + +[report issue]
    +
    +

    on_piece_failed() on_piece_pass()

     virtual void on_piece_failed (piece_index_t);
     virtual void on_piece_pass (piece_index_t);
    @@ -748,7 +748,7 @@ 

    on_piece_pass() on_piece_failed()

    called when a piece that this peer participated in either fails or passes the hash_check

    [report issue]
    -
    +

    tick()

     virtual void tick ();
    @@ -771,8 +771,8 @@ 

    crypto_plugin

     struct crypto_plugin
     {
    -   virtual void set_outgoing_key (span<char const> key) = 0;
        virtual void set_incoming_key (span<char const> key) = 0;
    +   virtual void set_outgoing_key (span<char const> key) = 0;
        encrypt (span<span<char>> /*send_vec*/) = 0;
        virtual std::tuple<int, int, int> decrypt (span<span<char>> /*receive_vec*/) = 0;
     };
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Resume_Data.html b/3rd/libtorrent-rasterbar/docs/reference-Resume_Data.html
    index fd2f6ed9..b4b92eb9 100644
    --- a/3rd/libtorrent-rasterbar/docs/reference-Resume_Data.html
    +++ b/3rd/libtorrent-rasterbar/docs/reference-Resume_Data.html
    @@ -4,7 +4,7 @@
     
     
     
    -
    +
     libtorrent
     
     
    @@ -25,31 +25,31 @@
     
     
     Version:
    -2.0.8
    +2.0.9
     
     
     

    home

    [report issue]

    read_resume_data()

    Declared in "libtorrent/read_resume_data.hpp"

    +add_torrent_params read_resume_data (bdecode_node const& rd
    +   , error_code& ec, int piece_limit = 0x200000);
    +add_torrent_params read_resume_data (bdecode_node const& rd
    +   , int piece_limit = 0x200000);
     add_torrent_params read_resume_data (span<char const> buffer
        , error_code& ec, load_torrent_limits const& cfg = {});
     add_torrent_params read_resume_data (span<char const> buffer
        , load_torrent_limits const& cfg = {});
    -add_torrent_params read_resume_data (bdecode_node const& rd
    -   , int piece_limit = 0x200000);
    -add_torrent_params read_resume_data (bdecode_node const& rd
    -   , error_code& ec, int piece_limit = 0x200000);
     

    these functions are used to parse resume data and populate the appropriate fields in an add_torrent_params object. This object can then be used to add @@ -71,21 +71,21 @@

    read_resume_data()

    write_resume_data() write_resume_data_buf()

    Declared in "libtorrent/write_resume_data.hpp"

    -std::vector<char> write_resume_data_buf (add_torrent_params const& atp);
     entry write_resume_data (add_torrent_params const& atp);
    +std::vector<char> write_resume_data_buf (add_torrent_params const& atp);
     

    this function turns the resume data in an add_torrent_params object into a bencoded structure

    - -[report issue]
    -
    -

    write_torrent_file_buf() write_torrent_file()

    + +[report issue]
    +
    +

    write_torrent_file() write_torrent_file_buf()

    Declared in "libtorrent/write_resume_data.hpp"

    -entry write_torrent_file (add_torrent_params const& atp, write_torrent_flags_t flags);
     entry write_torrent_file (add_torrent_params const& atp);
     std::vector<char> write_torrent_file_buf (add_torrent_params const& atp
        , write_torrent_flags_t flags);
    +entry write_torrent_file (add_torrent_params const& atp, write_torrent_flags_t flags);
     

    writes only the fields to create a .torrent file. This function may fail with a std::system_error exception if:

    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Session.html b/3rd/libtorrent-rasterbar/docs/reference-Session.html index a6124e95..d0dfa586 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Session.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Session.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,69 +25,69 @@ Version: -2.0.8 +2.0.9

    home

    Table of contents

    [report issue]
    @@ -115,15 +115,15 @@

    session_handle

    void set_dht_state (dht::dht_state&& st); torrent_handle find_torrent (sha1_hash const& info_hash) const; std::vector<torrent_handle> get_torrents () const; - torrent_handle add_torrent (add_torrent_params&& params, error_code& ec); torrent_handle add_torrent (add_torrent_params const& params, error_code& ec); torrent_handle add_torrent (add_torrent_params const& params); + void async_add_torrent (add_torrent_params const& params); void async_add_torrent (add_torrent_params&& params); + torrent_handle add_torrent (add_torrent_params&& params, error_code& ec); torrent_handle add_torrent (add_torrent_params&& params); - void async_add_torrent (add_torrent_params const& params); - void resume (); void pause (); bool is_paused () const; + void resume (); bool is_dht_running () const; void set_dht_storage (dht::dht_storage_constructor_type sc); void add_dht_node (std::pair<std::string, int> const& node); @@ -140,17 +140,17 @@

    session_handle

    void dht_live_nodes (sha1_hash const& nid); void dht_sample_infohashes (udp::endpoint const& ep, sha1_hash const& target); void dht_direct_request (udp::endpoint const& ep, entry const& e, client_data_t userdata = {}); - void add_extension (std::shared_ptr<plugin> ext); void add_extension (std::function<std::shared_ptr<torrent_plugin>( torrent_handle const&, client_data_t)> ext); - void set_ip_filter (ip_filter f); + void add_extension (std::shared_ptr<plugin> ext); ip_filter get_ip_filter () const; + void set_ip_filter (ip_filter f); void set_port_filter (port_filter const& f); - unsigned short ssl_listen_port () const; unsigned short listen_port () const; bool is_listening () const; - void set_peer_class_filter (ip_filter const& f); + unsigned short ssl_listen_port () const; ip_filter get_peer_class_filter () const; + void set_peer_class_filter (ip_filter const& f); peer_class_type_filter get_peer_class_type_filter () const; void set_peer_class_type_filter (peer_class_type_filter const& f); peer_class_t create_peer_class (char const* name); @@ -159,8 +159,8 @@

    session_handle

    void set_peer_class (peer_class_t cid, peer_class_info const& pci); void remove_torrent (const torrent_handle&, remove_flags_t = {}); void apply_settings (settings_pack&&); - settings_pack get_settings () const; void apply_settings (settings_pack const&); + settings_pack get_settings () const; void set_alert_notify (std::function<void()> const& fun); void pop_alerts (std::vector<alert*>* alerts); alert* wait_for_alert (time_duration max_wait); @@ -292,10 +292,10 @@

    set_dht_state()

    set the DHT state for the session. This will be taken into account the next time the DHT is started, as if it had been passed in via the session_params on startup.

    - -[report issue]
    -
    -

    find_torrent() get_torrents()

    + +[report issue]
    +
    +

    get_torrents() find_torrent()

     torrent_handle find_torrent (sha1_hash const& info_hash) const;
     std::vector<torrent_handle> get_torrents () const;
    @@ -308,17 +308,17 @@ 

    find_torrent() get_torrents()

    not.

    get_torrents() returns a vector of torrent_handles to all the torrents currently in the session.

    - -[report issue]
    -
    -

    add_torrent() async_add_torrent()

    + +[report issue]
    +
    +

    async_add_torrent() add_torrent()

    -torrent_handle add_torrent (add_torrent_params&& params, error_code& ec);
     torrent_handle add_torrent (add_torrent_params const& params, error_code& ec);
     torrent_handle add_torrent (add_torrent_params const& params);
    +void async_add_torrent (add_torrent_params const& params);
     void async_add_torrent (add_torrent_params&& params);
    +torrent_handle add_torrent (add_torrent_params&& params, error_code& ec);
     torrent_handle add_torrent (add_torrent_params&& params);
    -void async_add_torrent (add_torrent_params const& params);
     

    You add torrents through the add_torrent() function where you give an object with all the parameters. The add_torrent() overloads will block @@ -352,9 +352,9 @@

    add_torrent() async_add_torrent()

    is_paused() pause() resume()

    -void resume ();
     void pause ();
     bool is_paused () const;
    +void resume ();
     

    Pausing the session has the same effect as pausing every torrent in it, except that torrents will not be resumed by the auto-manage @@ -404,7 +404,7 @@

    dht_get_item()

    query the DHT for an immutable item at the target hash. the result is posted as a dht_immutable_item_alert.

    [report issue]
    -
    +

    dht_get_item()

     void dht_get_item (std::array<char, 32> key
    @@ -426,7 +426,7 @@ 

    dht_put_item()

    up again. It's just the SHA-1 hash of the bencoded form of the structure.

    [report issue]
    -
    +

    dht_put_item()

     void dht_put_item (std::array<char, 32> key
    @@ -470,10 +470,10 @@ 

    dht_put_item()

    must first retrieve it, then modify it, then write it back. The way the DHT works, it is natural to always do a lookup before storing and calling the callback in between is convenient.

    - -[report issue]
    -
    -

    dht_get_peers() dht_announce()

    + +[report issue]
    +
    +

    dht_announce() dht_get_peers()

     void dht_get_peers (sha1_hash const& info_hash);
     void dht_announce (sha1_hash const& info_hash, int port = 0, dht::announce_flags_t flags = {});
    @@ -528,9 +528,9 @@ 

    dht_direct_request()

    add_extension()

    -void add_extension (std::shared_ptr<plugin> ext);
     void add_extension (std::function<std::shared_ptr<torrent_plugin>(
           torrent_handle const&, client_data_t)> ext);
    +void add_extension (std::shared_ptr<plugin> ext);
     

    This function adds an extension to this session. The argument is a function object that is called with a torrent_handle and which should @@ -571,8 +571,8 @@

    add_extension()

    set_ip_filter() get_ip_filter()

    -void set_ip_filter (ip_filter f);
     ip_filter get_ip_filter () const;
    +void set_ip_filter (ip_filter f);
     

    Sets a filter that will be used to reject and accept incoming as well as outgoing connections based on their originating ip address. The @@ -597,9 +597,9 @@

    set_port_filter()

    listen_port() is_listening() ssl_listen_port()

    -unsigned short ssl_listen_port () const;
     unsigned short listen_port () const;
     bool is_listening () const;
    +unsigned short ssl_listen_port () const;
     

    is_listening() will tell you whether or not the session has successfully opened a listening port. If it hasn't, this function will @@ -607,13 +607,13 @@

    listen_port() is_listening() ssl_listen_port()

    settings_pack::listen_interfaces to try another interface and port to bind to.

    listen_port() returns the port we ended up listening on.

    - -[report issue]
    -
    -

    get_peer_class_filter() set_peer_class_filter()

    + +[report issue]
    +
    +

    set_peer_class_filter() get_peer_class_filter()

    -void set_peer_class_filter (ip_filter const& f);
     ip_filter get_peer_class_filter () const;
    +void set_peer_class_filter (ip_filter const& f);
     

    Sets the peer class filter for this session. All new peer connections will take this into account and be added to the peer classes specified @@ -641,10 +641,10 @@

    get_peer_class_filter() set_peer_class_filter()

    representing peer classes in the peer_class_filter are 32 bits.

    The get_peer_class_filter() function returns the current filter.

    For more information, see peer classes.

    - -[report issue]
    -
    -

    set_peer_class_type_filter() get_peer_class_type_filter()

    + +[report issue]
    +
    +

    get_peer_class_type_filter() set_peer_class_type_filter()

     peer_class_type_filter get_peer_class_type_filter () const;
     void set_peer_class_type_filter (peer_class_type_filter const& f);
    @@ -694,10 +694,10 @@ 

    delete_peer_class()

    peer classes will be properly destructed when the session object destructs.

    For more information on peer classes, see peer classes.

    - -[report issue]
    -
    -

    get_peer_class() set_peer_class()

    + +[report issue]
    +
    +

    set_peer_class() get_peer_class()

     peer_class_info get_peer_class (peer_class_t cid) const;
     void set_peer_class (peer_class_t cid, peer_class_info const& pci);
    @@ -748,23 +748,23 @@ 

    remove_torrent()

    large state_update to be posted. When removing all torrents, it is advised to remove them from the back of the queue, to minimize the shifting.

    - -[report issue]
    -
    -

    apply_settings() get_settings()

    + +[report issue]
    +
    +

    get_settings() apply_settings()

     void apply_settings (settings_pack&&);
    -settings_pack get_settings () const;
     void apply_settings (settings_pack const&);
    +settings_pack get_settings () const;
     

    Applies the settings specified by the settings_pack s. This is an asynchronous operation that will return immediately and actually apply the settings to the main thread of libtorrent some time later.

    - + -[report issue]
    -
    -

    set_alert_notify() pop_alerts() wait_for_alert()

    +[report issue]
    +
    +

    wait_for_alert() pop_alerts() set_alert_notify()

     void set_alert_notify (std::function<void()> const& fun);
     void pop_alerts (std::vector<alert*>* alerts);
    @@ -822,10 +822,10 @@ 

    set_alert_notify() pop_alerts() wait_for_alert()

    The type of an alert is returned by the polymorphic function alert::type() but can also be queries from a concrete type via T::alert_type, as a static constant.

    - -[report issue]
    -
    -

    add_port_mapping() delete_port_mapping()

    + +[report issue]
    +
    +

    delete_port_mapping() add_port_mapping()

     void delete_port_mapping (port_mapping_t handle);
     std::vector<port_mapping_t> add_port_mapping (portmap_protocol t, int external_port, int local_port);
    @@ -917,24 +917,24 @@ 

    session_proxy

    struct session_proxy { session_proxy& operator= (session_proxy const&) &; - session_proxy (session_proxy&&) noexcept; - session_proxy (); - session_proxy& operator= (session_proxy&&) & noexcept; session_proxy (session_proxy const&); + session_proxy& operator= (session_proxy&&) & noexcept; ~session_proxy (); + session_proxy (); + session_proxy (session_proxy&&) noexcept; };
    - -[report issue]
    -

    operator=() session_proxy() ~session_proxy()

    + +[report issue]
    +

    session_proxy() ~session_proxy() operator=()

     session_proxy& operator= (session_proxy const&) &;
    -session_proxy (session_proxy&&) noexcept;
    -session_proxy ();
    -session_proxy& operator= (session_proxy&&) & noexcept;
     session_proxy (session_proxy const&);
    +session_proxy& operator= (session_proxy&&) & noexcept;
     ~session_proxy ();
    +session_proxy ();
    +session_proxy (session_proxy&&) noexcept;
     

    default constructor, does not refer to any session implementation object.

    @@ -957,24 +957,24 @@

    session

    struct session : session_handle { session (session_params const& params, session_flags_t flags); - session (); explicit session (session_params&& params); + session (); explicit session (session_params const& params); session (session_params&& params, session_flags_t flags); session (session_params const& params, io_context& ios); + session (session_params&& params, io_context& ios, session_flags_t); session (session_params const& params, io_context& ios, session_flags_t); session (session_params&& params, io_context& ios); - session (session_params&& params, io_context& ios, session_flags_t); ~session (); session_proxy abort (); };
    -[report issue]
    +[report issue]

    session()

     session (session_params const& params, session_flags_t flags);
    -session ();
     explicit session (session_params&& params);
    +session ();
     explicit session (session_params const& params);
     session (session_params&& params, session_flags_t flags);
     
    @@ -987,13 +987,13 @@

    session()

    add_default_plugins do not have an affect on constructors that take a session_params object. It already contains the plugins to use.

    [report issue]
    -
    +

    session()

     session (session_params const& params, io_context& ios);
    +session (session_params&& params, io_context& ios, session_flags_t);
     session (session_params const& params, io_context& ios, session_flags_t);
     session (session_params&& params, io_context& ios);
    -session (session_params&& params, io_context& ios, session_flags_t);
     

    Overload of the constructor that takes an external io_context to run the session object on. This is primarily useful for tests that may want @@ -1010,7 +1010,7 @@

    session()

    destruct the session_proxy object.

    [report issue]
    -
    +

    ~session()

     ~session ();
    @@ -1051,13 +1051,13 @@ 

    session_params

     struct session_params
     {
    -   session_params ();
    -   session_params (settings_pack&& sp);
        session_params (settings_pack const& sp);
    -   session_params (settings_pack const& sp
    -      , std::vector<std::shared_ptr<plugin>> exts);
    +   session_params (settings_pack&& sp);
    +   session_params ();
        session_params (settings_pack&& sp
           , std::vector<std::shared_ptr<plugin>> exts);
    +   session_params (settings_pack const& sp
    +      , std::vector<std::shared_ptr<plugin>> exts);
     
        settings_pack settings;
        std::vector<std::shared_ptr<plugin>> extensions;
    @@ -1068,24 +1068,24 @@ 

    session_params

    libtorrent::ip_filter ip_filter; };
    -[report issue]
    +[report issue]

    session_params()

    -session_params ();
    -session_params (settings_pack&& sp);
     session_params (settings_pack const& sp);
    +session_params (settings_pack&& sp);
    +session_params ();
     

    This constructor can be used to start with the default plugins (ut_metadata, ut_pex and smart_ban). Pass a settings_pack to set the initial settings when the session starts.

    [report issue]
    -
    +

    session_params()

    -session_params (settings_pack const& sp
    -      , std::vector<std::shared_ptr<plugin>> exts);
     session_params (settings_pack&& sp
           , std::vector<std::shared_ptr<plugin>> exts);
    +session_params (settings_pack const& sp
    +      , std::vector<std::shared_ptr<plugin>> exts);
     

    This constructor helps to configure the set of initial plugins to be added to the session before it's started.

    @@ -1121,22 +1121,22 @@

    session_params()

    the IP filter to use for the session. This restricts which peers are allowed to connect. As if passed to set_ip_filter().
    + - -[report issue]
    +[report issue]
    -
    -

    write_session_params() write_session_params_buf() read_session_params()

    +
    +

    read_session_params() write_session_params() write_session_params_buf()

    Declared in "libtorrent/session_params.hpp"

    -session_params read_session_params (span<char const> buf
    -   , save_state_flags_t flags = save_state_flags_t::all());
     entry write_session_params (session_params const& sp
        , save_state_flags_t flags = save_state_flags_t::all());
     std::vector<char> write_session_params_buf (session_params const& sp
        , save_state_flags_t flags = save_state_flags_t::all());
     session_params read_session_params (bdecode_node const& e
        , save_state_flags_t flags = save_state_flags_t::all());
    +session_params read_session_params (span<char const> buf
    +   , save_state_flags_t flags = save_state_flags_t::all());
     

    These functions serialize and de-serialize a session_params object to and from bencoded form. The session_params object is used to initialize a new diff --git a/3rd/libtorrent-rasterbar/docs/reference-Settings.html b/3rd/libtorrent-rasterbar/docs/reference-Settings.html index 9d48bdc1..6d15b1e1 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Settings.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Settings.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,35 +25,35 @@ Version: -2.0.8 +2.0.9

    home

    You have some control over session configuration through the session::apply_settings() @@ -344,7 +344,10 @@

    settings_pack

    sets the i2p SAM bridge to connect to. set the port with the -i2p_port setting.

    +i2p_port setting. Unless this is set, i2p torrents are not +supported. This setting is separate from the other proxy settings +since i2p torrents and their peers are orthogonal. You can have +i2p peers as well as regular peers via a proxy.

    @@ -360,7 +363,7 @@

    settings_pack

    - +
    peer_fingerprint string-LT2080--LT2090-
    @@ -2910,6 +2913,10 @@

    settings_pack

    default (i.e. don't change the buffer sizes). The socket buffer sizes are changed using setsockopt() with SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER.

    +

    Note that uTP peers share a single UDP socket buffer for each of the +listen_interfaces, along with DHT and UDP tracker traffic. +If the buffer size is too small for the combined traffic through the +socket, packets may be dropped.

    @@ -4512,6 +4519,47 @@

    settings_pack

    when using mmap_disk_io, files smaller than this number of blocks will not be memory mapped, but will use normal pread/pwrite operations. This file size limit is specified in 16 kiB blocks.

    + + + +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
    nametypedefault
    i2p_inbound_quantityint3
    i2p_outbound_quantityint3
    i2p_inbound_lengthint3
    i2p_outbound_lengthint3
    +

    Configures the SAM session +quantity of I2P inbound and outbound tunnels [1..16]. +number of hops for I2P inbound and outbound tunnels [0..7] +Changing these will not trigger a reconnect to the SAM bridge, +they will take effect the next time the SAM connection is +re-established (by restarting or changing i2p_hostname or +i2p_port).

     struct settings_pack final : settings_interface
     {
    @@ -4520,14 +4568,14 @@ 

    settings_pack

    , std::vector<void(aux::session_impl::*)()>*); void set_str (int name, std::string val) override; void set_int (int name, flags::bitfield_flag<Type, Tag> const val); - void set_int (int name, int val) override; void set_bool (int name, bool val) override; + void set_int (int name, int val) override; bool has_val (int name) const override; void clear (); void clear (int name); + int get_int (int name) const override; bool get_bool (int name) const override; std::string const& get_str (int name) const override; - int get_int (int name) const override; void for_each (Fun&& f) const; enum type_bases @@ -4602,19 +4650,18 @@

    settings_pack

    socks5_pw, http, http_pw, - i2p_proxy, }; };
    - -[report issue]
    -

    set_str() set_bool() set_int()

    + +[report issue]
    +

    set_bool() set_int() set_str()

     void set_str (int name, std::string val) override;
     void set_int (int name, flags::bitfield_flag<Type, Tag> const val);
    -void set_int (int name, int val) override;
     void set_bool (int name, bool val) override;
    +void set_int (int name, int val) override;
     

    set a configuration option in the settings_pack. name is one of the enum values from string_types, int_types or bool_types. They must @@ -4636,21 +4683,21 @@

    clear()

    clear the settings pack from all settings

    [report issue]
    -
    +

    clear()

     void clear (int name);
     

    clear a specific setting from the pack

    - + -[report issue]
    -
    -

    get_bool() get_str() get_int()

    +[report issue]
    +
    +

    get_int() get_str() get_bool()

    +int get_int (int name) const override;
     bool get_bool (int name) const override;
     std::string const& get_str (int name) const override;
    -int get_int (int name) const override;
     

    queries the current configuration option from the settings_pack. name is one of the enumeration values from string_types, int_types @@ -5015,10 +5062,6 @@

    enum proxy_type_t

    The server is assumed to be an HTTP proxy that requires user authorization. The username and password will be sent to the proxy. -i2p_proxy -6 -route through a i2p SAM proxy - @@ -5028,8 +5071,8 @@

    enum proxy_type_t

    name_for_setting() setting_by_name()

    Declared in "libtorrent/settings_pack.hpp"

    -char const* name_for_setting (int s);
     int setting_by_name (string_view name);
    +char const* name_for_setting (int s);
     

    converts a setting integer (from the enums string_types, int_types or bool_types) to a string, and vice versa.

    @@ -5041,10 +5084,10 @@

    default_settings()

    settings_pack default_settings ();

    returns a settings_pack with every setting set to its default value

    - -[report issue]
    -
    -

    high_performance_seed() min_memory_usage()

    + +[report issue]
    +
    +

    min_memory_usage() high_performance_seed()

    Declared in "libtorrent/session.hpp"

     settings_pack min_memory_usage ();
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Stats.html b/3rd/libtorrent-rasterbar/docs/reference-Stats.html
    index f2b50ac7..1a772a64 100644
    --- a/3rd/libtorrent-rasterbar/docs/reference-Stats.html
    +++ b/3rd/libtorrent-rasterbar/docs/reference-Stats.html
    @@ -4,7 +4,7 @@
     
     
     
    -
    +
     libtorrent
     
     
    @@ -25,21 +25,21 @@
     
     
     Version:
    -2.0.8
    +2.0.9
     
     
     

    home

    [report issue]
    @@ -74,10 +74,10 @@

    counters

    struct counters { counters () ; - counters (counters const&) ; counters& operator= (counters const&) & ; - std::int64_t operator[] (int i) const ; + counters (counters const&) ; std::int64_t inc_stats_counter (int c, std::int64_t value = 1) ; + std::int64_t operator[] (int i) const ; void blend_stats_counter (int c, std::int64_t value, int ratio) ; void set_value (int c, std::int64_t value) ; }; @@ -86,8 +86,8 @@

    counters

    [report issue]

    inc_stats_counter() operator[]()

    -std::int64_t operator[] (int i) const ;
     std::int64_t inc_stats_counter (int c, std::int64_t value = 1) ;
    +std::int64_t operator[] (int i) const ;
     

    returns the new value

    [report issue]
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Storage.html b/3rd/libtorrent-rasterbar/docs/reference-Storage.html index 8e782c2f..8683e60a 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Storage.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Storage.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,58 +25,59 @@ Version: -2.0.8 +2.0.9

    home

    Table of contents

    [report issue]
    @@ -151,15 +152,15 @@

    file_storage

    , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); + void add_file (std::string const& path, std::int64_t file_size + , file_flags_t file_flags = {} + , std::time_t mtime = 0, string_view symlink_path = string_view() + , char const* root_hash = nullptr); void add_file_borrow (string_view filename , std::string const& path, std::int64_t file_size , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); - void add_file (std::string const& path, std::int64_t file_size - , file_flags_t file_flags = {} - , std::time_t mtime = 0, string_view symlink_path = string_view() - , char const* root_hash = nullptr); void rename_file (file_index_t index, std::string const& new_filename); std::vector<file_slice> map_block (piece_index_t piece, std::int64_t offset , std::int64_t size) const; @@ -178,25 +179,26 @@

    file_storage

    int piece_size (piece_index_t index) const; int piece_size2 (piece_index_t index) const; int blocks_in_piece2 (piece_index_t index) const; + int blocks_per_piece () const; std::string const& name () const; void set_name (std::string const& n); void swap (file_storage& ti) noexcept; void canonicalize (); + char const* root_ptr (file_index_t const index) const; + string_view file_name (file_index_t index) const; std::string symlink (file_index_t index) const; + std::int64_t file_size (file_index_t index) const; sha1_hash hash (file_index_t index) const; + sha256_hash root (file_index_t index) const; std::int64_t file_offset (file_index_t index) const; + std::string file_path (file_index_t index, std::string const& save_path = "") const; std::time_t mtime (file_index_t index) const; - std::int64_t file_size (file_index_t index) const; - char const* root_ptr (file_index_t const index) const; bool pad_file_at (file_index_t index) const; - sha256_hash root (file_index_t index) const; - string_view file_name (file_index_t index) const; - std::string file_path (file_index_t index, std::string const& save_path = "") const; - int file_num_pieces (file_index_t index) const; int file_num_blocks (file_index_t index) const; + int file_num_pieces (file_index_t index) const; index_range<piece_index_t::diff_type> file_piece_range (file_index_t) const; - int file_first_block_node (file_index_t index) const; int file_first_piece_node (file_index_t index) const; + int file_first_block_node (file_index_t index) const; std::uint32_t file_path_hash (file_index_t index, std::string const& save_path) const; void all_path_hashes (std::unordered_set<std::uint32_t>& table) const; file_flags_t file_flags (file_index_t index) const; @@ -246,15 +248,15 @@

    add_file_borrow() add_file()

    , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); +void add_file (std::string const& path, std::int64_t file_size + , file_flags_t file_flags = {} + , std::time_t mtime = 0, string_view symlink_path = string_view() + , char const* root_hash = nullptr); void add_file_borrow (string_view filename , std::string const& path, std::int64_t file_size , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); -void add_file (std::string const& path, std::int64_t file_size - , file_flags_t file_flags = {} - , std::time_t mtime = 0, string_view symlink_path = string_view() - , char const* root_hash = nullptr);

    Adds a file to the file storage. The add_file_borrow version expects that filename is the file name (without a path) of @@ -360,10 +362,10 @@

    total_size()

    std::int64_t total_size () const;

    returns the total number of bytes all the files in this torrent spans

    - -[report issue]
    -
    -

    set_num_pieces() num_pieces()

    + +[report issue]
    +
    +

    num_pieces() set_num_pieces()

     int num_pieces () const;
     void set_num_pieces (int n);
    @@ -429,6 +431,14 @@ 

    blocks_in_piece2()

    int blocks_in_piece2 (piece_index_t index) const;

    returns the number of blocks in the specified piece, for v2 torrents.

    +[report issue]
    +
    +

    blocks_per_piece()

    +
    +int blocks_per_piece () const;
    +
    +

    returns the number of blocks there are in the typical piece. There +may be fewer in the last piece)

    [report issue]
    @@ -454,29 +464,29 @@

    canonicalize()

    arrange files and padding to match the canonical form required by BEP 52

    + + - - + + - - - -[report issue]
    - + -
    -

    file_piece_range() file_num_blocks() file_num_pieces()

    + +[report issue]
    +
    +

    file_num_blocks() file_num_pieces() file_piece_range()

    -int file_num_pieces (file_index_t index) const;
     int file_num_blocks (file_index_t index) const;
    +int file_num_pieces (file_index_t index) const;
     index_range<piece_index_t::diff_type> file_piece_range (file_index_t) const;
     

    Returns the number of pieces or blocks the file at index spans, @@ -523,8 +533,8 @@

    file_piece_range() file_num_blocks() file_num_pieces()

    file_first_piece_node() file_first_block_node()

    -int file_first_block_node (file_index_t index) const;
     int file_first_piece_node (file_index_t index) const;
    +int file_first_block_node (file_index_t index) const;
     

    index of first piece node in the merkle tree

    [report issue]
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Handle.html b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Handle.html index dcb6d5ef..4a6315b5 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Handle.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Handle.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,69 +25,69 @@ Version: -2.0.8 +2.0.9

    home

    Table of contents

    [report issue]
    @@ -98,8 +98,8 @@

    block_info

     struct block_info
     {
    -   tcp::endpoint peer () const;
        void set_peer (tcp::endpoint const& ep);
    +   tcp::endpoint peer () const;
     
        enum block_state_t
        {
    @@ -119,8 +119,8 @@ 

    block_info

    [report issue]

    peer() set_peer()

    -tcp::endpoint peer () const;
     void set_peer (tcp::endpoint const& ep);
    +tcp::endpoint peer () const;
     

    The peer is the ip address of the peer this block was downloaded from.

    [report issue]
    @@ -226,7 +226,9 @@

    partial_piece_info

    Warning

    This is a pointer that points to an array that's owned by the session object. The next time -get_download_queue() is called, it will be invalidated.

    +get_download_queue() is called, it will be invalidated. +In the case of piece_info_alert, these pointers point into the alert +object itself, and will be invalidated when the alert destruct.

    @@ -270,19 +272,24 @@

    torrent_handle

    void read_piece (piece_index_t piece) const; bool have_piece (piece_index_t piece) const; void get_peer_info (std::vector<peer_info>& v) const; + void post_peer_info () const; + void post_status (status_flags_t flags = status_flags_t::all()) const; torrent_status status (status_flags_t flags = status_flags_t::all()) const; std::vector<partial_piece_info> get_download_queue () const; + void post_download_queue () const; void get_download_queue (std::vector<partial_piece_info>& queue) const; + void reset_piece_deadline (piece_index_t index) const; void clear_piece_deadlines () const; void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const; - void reset_piece_deadline (piece_index_t index) const; - std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const; void file_progress (std::vector<std::int64_t>& progress, file_progress_flags_t flags = {}) const; + std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const; + void post_file_progress (file_progress_flags_t flags) const; std::vector<open_file_state> file_status () const; void clear_error () const; + void post_trackers () const; + std::vector<announce_entry> trackers () const; void add_tracker (announce_entry const&) const; void replace_trackers (std::vector<announce_entry> const&) const; - std::vector<announce_entry> trackers () const; void remove_url_seed (std::string const& url) const; void add_url_seed (std::string const& url) const; std::set<std::string> url_seeds () const; @@ -294,55 +301,57 @@

    torrent_handle

    , client_data_t userdata = client_data_t{}); bool set_metadata (span<char const> metadata) const; bool is_valid () const; - void resume () const; void pause (pause_flags_t flags = {}) const; - void set_flags (torrent_flags_t flags, torrent_flags_t mask) const; + void resume () const; torrent_flags_t flags () const; + void set_flags (torrent_flags_t flags, torrent_flags_t mask) const; void set_flags (torrent_flags_t flags) const; void unset_flags (torrent_flags_t flags) const; void flush_cache () const; void force_recheck () const; void save_resume_data (resume_data_flags_t flags = {}) const; + bool need_save_resume_data (resume_data_flags_t flags) const; bool need_save_resume_data () const; + void queue_position_down () const; + queue_position_t queue_position () const; void queue_position_top () const; void queue_position_bottom () const; void queue_position_up () const; - queue_position_t queue_position () const; - void queue_position_down () const; void queue_position_set (queue_position_t p) const; + void set_ssl_certificate_buffer (std::string const& certificate + , std::string const& private_key + , std::string const& dh_params); void set_ssl_certificate (std::string const& certificate , std::string const& private_key , std::string const& dh_params , std::string const& passphrase = ""); - void set_ssl_certificate_buffer (std::string const& certificate - , std::string const& private_key - , std::string const& dh_params); - std::shared_ptr<const torrent_info> torrent_file () const; std::shared_ptr<torrent_info> torrent_file_with_hashes () const; + std::shared_ptr<const torrent_info> torrent_file () const; std::vector<std::vector<sha256_hash>> piece_layers () const; + void post_piece_availability () const; void piece_availability (std::vector<int>& avail) const; void prioritize_pieces (std::vector<download_priority_t> const& pieces) const; + download_priority_t piece_priority (piece_index_t index) const; std::vector<download_priority_t> get_piece_priorities () const; - void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const; void piece_priority (piece_index_t index, download_priority_t priority) const; - download_priority_t piece_priority (piece_index_t index) const; + void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const; + void prioritize_files (std::vector<download_priority_t> const& files) const; void file_priority (file_index_t index, download_priority_t priority) const; std::vector<download_priority_t> get_file_priorities () const; download_priority_t file_priority (file_index_t index) const; - void prioritize_files (std::vector<download_priority_t> const& files) const; - void force_dht_announce () const; void force_lsd_announce () const; + void force_dht_announce () const; void force_reannounce (int seconds = 0, int idx = -1, reannounce_flags_t = {}) const; void scrape_tracker (int idx = -1) const; void set_download_limit (int limit) const; - void set_upload_limit (int limit) const; - int upload_limit () const; int download_limit () const; + int upload_limit () const; + void set_upload_limit (int limit) const; void connect_peer (tcp::endpoint const& adr, peer_source_flags_t source = {} , pex_flags_t flags = pex_encryption | pex_utp | pex_holepunch) const; void clear_peers (); - int max_uploads () const; void set_max_uploads (int max_uploads) const; + int max_uploads () const; void set_max_connections (int max_connections) const; int max_connections () const; void move_storage (std::string const& save_path @@ -352,8 +361,8 @@

    torrent_handle

    info_hash_t info_hashes () const; sha1_hash info_hash () const; bool operator< (const torrent_handle& h) const; - bool operator!= (const torrent_handle& h) const; bool operator== (const torrent_handle& h) const; + bool operator!= (const torrent_handle& h) const; std::uint32_t id () const; std::shared_ptr<torrent> native_handle () const; client_data_t userdata () const; @@ -374,10 +383,15 @@

    torrent_handle

    static constexpr resume_data_flags_t flush_disk_cache = 0_bit; static constexpr resume_data_flags_t save_info_dict = 1_bit; static constexpr resume_data_flags_t only_if_modified = 2_bit; + static constexpr resume_data_flags_t if_counters_changed = 3_bit; + static constexpr resume_data_flags_t if_download_progress = 4_bit; + static constexpr resume_data_flags_t if_config_changed = 5_bit; + static constexpr resume_data_flags_t if_state_changed = 6_bit; + static constexpr resume_data_flags_t if_metadata_changed = 7_bit; static constexpr reannounce_flags_t ignore_min_interval = 0_bit; }; -[report issue]
    +[report issue]

    torrent_handle()

     torrent_handle () noexcept = default;
    @@ -434,21 +448,30 @@ 

    have_piece()

    Returns true if this piece has been completely downloaded and written to disk, and false otherwise.

    -[report issue]
    -
    -

    get_peer_info()

    + +[report issue]
    +
    +

    post_peer_info() get_peer_info()

     void get_peer_info (std::vector<peer_info>& v) const;
    +void post_peer_info () const;
     
    -

    takes a reference to a vector that will be cleared and filled with one -entry for each peer connected to this torrent, given the handle is -valid. If the torrent_handle is invalid, it will throw -system_error exception. Each entry in the vector contains -information about that particular peer. See peer_info.

    -[report issue]
    -
    -

    status()

    +

    Query information about connected peers for this torrent. If the +torrent_handle is invalid, it will throw a system_error exception.

    +

    post_peer_info() is asynchronous and will trigger the posting of +a peer_info_alert. The alert contain a list of peer_info objects, one +for each connected peer.

    +

    get_peer_info() is synchronous and takes a reference to a vector +that will be cleared and filled with one entry for each peer +connected to this torrent, given the handle is valid. Each entry in +the vector contains information about that particular peer. See +peer_info.

    + +[report issue]
    +
    +

    status() post_status()

    +void post_status (status_flags_t flags = status_flags_t::all()) const;
     torrent_status status (status_flags_t flags = status_flags_t::all()) const;
     

    status() will return a structure with information about the status @@ -458,28 +481,39 @@

    status()

    Some information in there is relatively expensive to calculate, and if you're not interested in it (and see performance issues), you can filter them out.

    +

    The status() function will block until the internal libtorrent +thread responds with the torrent_status object. To avoid blocking, +instead call post_status(). It will trigger posting of a +state_update_alert with a single torrent_status object for this +torrent.

    +

    In order to get regular updates for torrents whose status changes, +consider calling session::post_torrent_updates()`` instead.

    By default everything is included. The flags you can use to decide what to include are defined in this class.

    -[report issue]
    -
    -

    get_download_queue()

    + +[report issue]
    +
    +

    post_download_queue() get_download_queue()

     std::vector<partial_piece_info> get_download_queue () const;
    +void post_download_queue () const;
     void get_download_queue (std::vector<partial_piece_info>& queue) const;
     
    -

    get_download_queue() returns a vector with information about pieces -that are partially downloaded or not downloaded but partially -requested. See partial_piece_info for the fields in the returned -vector.

    +

    post_download_queue() triggers a download_queue_alert to be +posted. +get_download_queue() is a synchronous call and returns a vector +with information about pieces that are partially downloaded or not +downloaded but partially requested. See partial_piece_info for the +fields in the returned vector.

    - -[report issue]
    -
    -

    set_piece_deadline() clear_piece_deadlines() reset_piece_deadline()

    + +[report issue]
    +
    +

    set_piece_deadline() reset_piece_deadline() clear_piece_deadlines()

    +void reset_piece_deadline (piece_index_t index) const;
     void clear_piece_deadlines () const;
     void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const;
    -void reset_piece_deadline (piece_index_t index) const;
     

    This function sets or resets the deadline associated with a specific piece index (index). libtorrent will attempt to download this @@ -498,12 +532,14 @@

    set_piece_deadline() clear_piece_deadlines() reset_piece_deadline()

    priority.

    clear_piece_deadlines() removes deadlines on all pieces in the torrent. As if reset_piece_deadline() was called on all pieces.

    -[report issue]
    -
    -

    file_progress()

    + +[report issue]
    +
    +

    post_file_progress() file_progress()

    -std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const;
     void file_progress (std::vector<std::int64_t>& progress, file_progress_flags_t flags = {}) const;
    +std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const;
    +void post_file_progress (file_progress_flags_t flags) const;
     

    This function fills in the supplied vector, or returns a vector, with the number of bytes downloaded of each file in this torrent. The @@ -540,17 +576,19 @@

    clear_error()

    If the torrent is in an error state (i.e. torrent_status::error is non-empty), this will clear the error and start the torrent again.

    + - -[report issue]
    -
    -

    trackers() add_tracker() replace_trackers()

    + +[report issue]
    +
    +

    post_trackers() trackers() replace_trackers() add_tracker()

    +void post_trackers () const;
    +std::vector<announce_entry> trackers () const;
     void add_tracker (announce_entry const&) const;
     void replace_trackers (std::vector<announce_entry> const&) const;
    -std::vector<announce_entry> trackers () const;
     
    -

    trackers() will return the list of trackers for this torrent. The +

    trackers() returns the list of trackers for this torrent. The announce entry contains both a string url which specify the announce url for the tracker as well as an int tier, which is specifies the order in which this tracker is tried. If you want @@ -559,6 +597,8 @@

    trackers() add_tracker() replace_trackers()

    one returned from trackers() and will replace it. If you want an immediate effect, you have to call force_reannounce(). See announce_entry.

    +

    post_trackers() is the asynchronous version of trackers(). It +will trigger a tracker_list_alert to be posted.

    add_tracker() will look if the specified tracker is already in the set. If it is, it doesn't do anything. If it's not in the current set of trackers, it will insert it in the tier specified in the @@ -566,11 +606,11 @@

    trackers() add_tracker() replace_trackers()

    The updated set of trackers will be saved in the resume data, and when a torrent is started with resume data, the trackers from the resume data will replace the original ones.

    + - -[report issue]
    -
    -

    remove_url_seed() url_seeds() add_url_seed()

    +[report issue]
    +
    +

    add_url_seed() remove_url_seed() url_seeds()

     void remove_url_seed (std::string const& url) const;
     void add_url_seed (std::string const& url) const;
    @@ -585,11 +625,11 @@ 

    remove_url_seed() url_seeds() add_url_seed()

    torrent. Note that URLs that fails may be removed automatically from the list.

    See http seeding for more information.

    - + -[report issue]
    -
    -

    remove_http_seed() http_seeds() add_http_seed()

    +[report issue]
    +
    +

    add_http_seed() http_seeds() remove_http_seed()

     std::set<std::string> http_seeds () const;
     void remove_http_seed (std::string const& url) const;
    @@ -648,8 +688,8 @@ 

    is_valid()

    pause() resume()

    -void resume () const;
     void pause (pause_flags_t flags = {}) const;
    +void resume () const;
     

    pause(), and resume() will disconnect all peers and reconnect all peers respectively. When a torrent is paused, it will however @@ -668,14 +708,14 @@

    pause() resume()

    not auto-managed first. Torrents are auto-managed by default when added to the session. For more information, see queuing.

    - -[report issue]
    -
    -

    set_flags() flags() unset_flags()

    + +[report issue]
    +
    +

    flags() unset_flags() set_flags()

    -void set_flags (torrent_flags_t flags, torrent_flags_t mask) const;
     torrent_flags_t flags () const;
    +void set_flags (torrent_flags_t flags, torrent_flags_t mask) const;
     void set_flags (torrent_flags_t flags) const;
     void unset_flags (torrent_flags_t flags) const;
     
    @@ -822,13 +862,18 @@

    save_resume_data()

    need_save_resume_data()

    +bool need_save_resume_data (resume_data_flags_t flags) const;
     bool need_save_resume_data () const;
     
    -

    This function returns true if any whole chunk has been downloaded -since the torrent was first loaded or since the last time the resume -data was saved. When saving resume data periodically, it makes sense -to skip any torrent which hasn't downloaded anything since the last -time.

    +

    This function returns true if anything that is stored in the resume +data has changed since the last time resume data was saved. +The overload that takes flags let you ask if specific categories +of properties have changed. These flags have the same behavior as in +the save_resume_data() call.

    +

    This is a blocking call. It will wait for a response from +libtorrent's main thread. A way to avoid blocking is to instead +call save_resume_data() directly, specifying the conditions under +which resume data should be saved.

    Note

    A torrent's resume data is considered saved as soon as the @@ -837,18 +882,18 @@

    need_save_resume_data()

    meaningful.

    - + -[report issue]
    -
    -

    queue_position_down() queue_position() queue_position_top() queue_position_up() queue_position_bottom()

    +[report issue]
    +
    +

    queue_position_down() queue_position_top() queue_position() queue_position_up() queue_position_bottom()

    +void queue_position_down () const;
    +queue_position_t queue_position () const;
     void queue_position_top () const;
     void queue_position_bottom () const;
     void queue_position_up () const;
    -queue_position_t queue_position () const;
    -void queue_position_down () const;
     

    Every torrent that is added is assigned a queue position exactly one greater than the greatest queue position of all existing torrents. @@ -875,18 +920,18 @@

    queue_position_set()

    updates the position in the queue for this torrent. The relative order of all other torrents remain intact but their numerical queue position shifts to make space for this torrent's new position

    - -[report issue]
    -
    -

    set_ssl_certificate() set_ssl_certificate_buffer()

    + +[report issue]
    +
    +

    set_ssl_certificate_buffer() set_ssl_certificate()

    +void set_ssl_certificate_buffer (std::string const& certificate
    +      , std::string const& private_key
    +      , std::string const& dh_params);
     void set_ssl_certificate (std::string const& certificate
           , std::string const& private_key
           , std::string const& dh_params
           , std::string const& passphrase = "");
    -void set_ssl_certificate_buffer (std::string const& certificate
    -      , std::string const& private_key
    -      , std::string const& dh_params);
     

    For SSL torrents, use this to specify a path to a .pem file to use as this client's certificate. The certificate must be signed by the @@ -910,13 +955,13 @@

    set_ssl_certificate() set_ssl_certificate_buffer()

    If you receive a torrent_need_cert_alert, you need to call this to provide a valid cert. If you don't have a cert you won't be allowed to connect to any peers.

    - -[report issue]
    -
    -

    torrent_file_with_hashes() torrent_file()

    + +[report issue]
    +
    +

    torrent_file() torrent_file_with_hashes()

    -std::shared_ptr<const torrent_info> torrent_file () const;
     std::shared_ptr<torrent_info> torrent_file_with_hashes () const;
    +std::shared_ptr<const torrent_info> torrent_file () const;
     

    torrent_file() returns a pointer to the torrent_info object associated with this torrent. The torrent_info object may be a copy @@ -956,30 +1001,34 @@

    piece_layers()

    v1 torrent (and doesn't have any piece layers) it returns an empty vector. This is a blocking call that will synchronize with the libtorrent network thread.

    -[report issue]
    -
    -

    piece_availability()

    + +[report issue]
    +
    +

    post_piece_availability() piece_availability()

    +void post_piece_availability () const;
     void piece_availability (std::vector<int>& avail) const;
     
    -

    Fills the specified std::vector<int> with the availability for -each piece in this torrent. libtorrent does not keep track of -availability for seeds, so if the torrent is seeding the availability -for all pieces is reported as 0.

    The piece availability is the number of peers that we are connected that has advertised having a particular piece. This is the information that libtorrent uses in order to prefer picking rare pieces.

    - +

    post_piece_availability() will trigger a piece_availability_alert +to be posted.

    +

    piece_availability() fills the specified std::vector<int> +with the availability for each piece in this torrent. libtorrent does +not keep track of availability for seeds, so if the torrent is +seeding the availability for all pieces is reported as 0.

    -[report issue]
    -
    -

    prioritize_pieces() get_piece_priorities() piece_priority()

    + +[report issue]
    +
    +

    get_piece_priorities() piece_priority() prioritize_pieces()

     void prioritize_pieces (std::vector<download_priority_t> const& pieces) const;
    +download_priority_t piece_priority (piece_index_t index) const;
     std::vector<download_priority_t> get_piece_priorities () const;
    -void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const;
     void piece_priority (piece_index_t index, download_priority_t priority) const;
    -download_priority_t piece_priority (piece_index_t index) const;
    +void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const;
     

    These functions are used to set and get the priority of individual pieces. By default all pieces have priority 4. That means that the @@ -1015,10 +1064,10 @@

    prioritize_pieces() get_piece_priorities() piece_priority()

    get_file_priorities() prioritize_files() file_priority()

    +void prioritize_files (std::vector<download_priority_t> const& files) const;
     void file_priority (file_index_t index, download_priority_t priority) const;
     std::vector<download_priority_t> get_file_priorities () const;
     download_priority_t file_priority (file_index_t index) const;
    -void prioritize_files (std::vector<download_priority_t> const& files) const;
     

    index must be in the range [0, number_of_files).

    file_priority() queries or sets the priority of file index.

    @@ -1050,13 +1099,13 @@

    get_file_priorities() prioritize_files() file_priority()

    supported. If a file has its priority set to 0 after it has already been created, it will not be moved into the partfile.

    - -[report issue]
    -
    -

    force_lsd_announce() force_dht_announce() force_reannounce()

    + +[report issue]
    +
    +

    force_lsd_announce() force_reannounce() force_dht_announce()

    -void force_dht_announce () const;
     void force_lsd_announce () const;
    +void force_dht_announce () const;
     void force_reannounce (int seconds = 0, int idx = -1, reannounce_flags_t = {}) const;
     

    force_reannounce() will force this torrent to do another tracker @@ -1089,17 +1138,17 @@

    scrape_tracker()

    num_incomplete fields in the torrent_status struct once it completes. When it completes, it will generate a scrape_reply_alert. If it fails, it will generate a scrape_failed_alert.

    - - -[report issue]
    -
    -

    set_download_limit() set_upload_limit() upload_limit() download_limit()

    + + +[report issue]
    +
    +

    upload_limit() download_limit() set_upload_limit() set_download_limit()

     void set_download_limit (int limit) const;
    -void set_upload_limit (int limit) const;
    -int upload_limit () const;
     int download_limit () const;
    +int upload_limit () const;
    +void set_upload_limit (int limit) const;
     

    set_upload_limit will limit the upload bandwidth used by this particular torrent to the limit you set. It is given as the number of @@ -1144,8 +1193,8 @@

    clear_peers()

    set_max_uploads() max_uploads()

    -int max_uploads () const;
     void set_max_uploads (int max_uploads) const;
    +int max_uploads () const;
     

    set_max_uploads() sets the maximum number of peers that's unchoked at the same time on this torrent. If you set this to -1, there will be @@ -1230,10 +1279,10 @@

    rename_file()

    Renames the file with the given index asynchronously. The rename operation is complete when either a file_renamed_alert or file_rename_failed_alert is posted.

    - -[report issue]
    -
    -

    info_hash() info_hashes()

    + +[report issue]
    +
    +

    info_hashes() info_hash()

     info_hash_t info_hashes () const;
     sha1_hash info_hash () const;
    @@ -1244,15 +1293,15 @@ 

    info_hash() info_hashes()

    The info_hash() returns the SHA-1 info-hash for v1 torrents and a truncated hash for v2 torrents. For the full v2 info-hash, use info_hashes() instead.

    - -[report issue]
    + +[report issue]
    -

    operator<() operator!=() operator==()

    +

    operator!=() operator==() operator<()

     bool operator< (const torrent_handle& h) const;
    -bool operator!= (const torrent_handle& h) const;
     bool operator== (const torrent_handle& h) const;
    +bool operator!= (const torrent_handle& h) const;
     

    comparison operators. The order of the torrents is unspecified but stable.

    @@ -1378,17 +1427,61 @@

    in_session()

    [report issue]
    save_info_dict
    the resume data will contain the metadata from the torrent file as -well. This is default for any torrent that's added without a -torrent file (such as a magnet link or a URL).
    +well. This is useful for clients that don't keep .torrent files +around separately, or for torrents that were added via a magnet link.
    [report issue]
    only_if_modified
    -
    if nothing significant has changed in the torrent since the last -time resume data was saved, fail this attempt. Significant changes -primarily include more data having been downloaded, file or piece -priorities having changed etc. If the resume data doesn't need -saving, a save_resume_data_failed_alert is posted with the error -resume_data_not_modified.
    +
    this flag has the same behavior as the combination of: +if_counters_changed | if_download_progress | if_config_changed | +if_state_changed | if_metadata_changed
    +
    +[report issue]
    +
    if_counters_changed
    +
    save resume data if any counters has changed since the last time +resume data was saved. This includes upload/download counters, active +time counters and scrape data. A torrent that is not paused will have +its active time counters incremented continuously.
    +
    +[report issue]
    +
    if_download_progress
    +
    save the resume data if any blocks have been downloaded since the +last time resume data was saved. This includes: +* checking existing files on disk +* downloading a block from a peer
    +
    +[report issue]
    +
    if_config_changed
    +
    save the resume data if configuration options changed since last time +the resume data was saved. This includes: +* file- or piece priorities +* upload- and download rate limits +* change max-uploads (unchoke slots) +* change max connection limit +* enable/disable peer-exchange, local service discovery or DHT +* enable/disable apply IP-filter +* enable/disable auto-managed +* enable/disable share-mode +* enable/disable sequential-mode +* files renamed +* storage moved (save_path changed)
    +
    +[report issue]
    +
    if_state_changed
    +
    save the resume data if torrent state has changed since last time the +resume data was saved. This includes: +* upload mode +* paused state +* super-seeding +* seed-mode
    +
    +[report issue]
    +
    if_metadata_changed
    +
    save the resume data if any metadata changed since the last time +resume data was saved. This includes: +* add/remove web seeds +* add/remove trackers +* receiving metadata for a magnet link
    [report issue]
    ignore_min_interval
    diff --git a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Info.html b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Info.html index df380f5d..3953f1b1 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Info.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Info.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,54 +25,55 @@ Version: -2.0.8 +2.0.9

    home

    Table of contents

    -
    +

    operator<()

     bool operator< (web_seed_entry const& e) const;
    @@ -200,49 +201,50 @@ 

    torrent_info

     class torrent_info
     {
    -   torrent_info (std::string const& filename, load_torrent_limits const& cfg);
    -   torrent_info (char const* buffer, int size, error_code& ec);
    -   torrent_info (std::string const& filename, error_code& ec);
    -   torrent_info (torrent_info const& t);
    -   torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    -   torrent_info (bdecode_node const& torrent_file, error_code& ec);
    -   torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
        explicit torrent_info (info_hash_t const& info_hash);
        torrent_info (char const* buffer, int size);
    -   explicit torrent_info (span<char const> buffer, from_span_t);
    -   explicit torrent_info (std::string const& filename);
        torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
    +   torrent_info (char const* buffer, int size, error_code& ec);
    +   torrent_info (std::string const& filename, error_code& ec);
    +   torrent_info (std::string const& filename, load_torrent_limits const& cfg);
    +   explicit torrent_info (std::string const& filename);
    +   torrent_info (bdecode_node const& torrent_file, error_code& ec);
        explicit torrent_info (bdecode_node const& torrent_file);
    +   torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    +   explicit torrent_info (span<char const> buffer, from_span_t);
    +   torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    +   torrent_info (torrent_info const& t);
        ~torrent_info ();
        file_storage const& orig_files () const;
        file_storage const& files () const;
        void rename_file (file_index_t index, std::string const& new_filename);
        void remap_files (file_storage const& f);
    -   void add_tracker (std::string const& url, int tier = 0);
        void add_tracker (std::string const& url, int tier
           , announce_entry::tracker_source source);
    -   void clear_trackers ();
    +   void add_tracker (std::string const& url, int tier = 0);
        std::vector<announce_entry> const& trackers () const;
    +   void clear_trackers ();
        std::vector<std::string> collections () const;
        std::vector<sha1_hash> similar_torrents () const;
    -   void add_url_seed (std::string const& url
    -      , std::string const& ext_auth = std::string()
    -      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
        void add_http_seed (std::string const& url
           , std::string const& extern_auth = std::string()
           , web_seed_entry::headers_t const& extra_headers = web_seed_entry::headers_t());
    -   void set_web_seeds (std::vector<web_seed_entry> seeds);
        std::vector<web_seed_entry> const& web_seeds () const;
    +   void set_web_seeds (std::vector<web_seed_entry> seeds);
    +   void add_url_seed (std::string const& url
    +      , std::string const& ext_auth = std::string()
    +      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
        std::int64_t total_size () const;
    -   int num_pieces () const;
        int piece_length () const;
    -   piece_index_t last_piece () const;
    +   int num_pieces () const;
    +   int blocks_per_piece () const;
        index_range<piece_index_t> piece_range () const;
        piece_index_t end_piece () const;
    -   sha1_hash info_hash () const noexcept;
    +   piece_index_t last_piece () const;
        info_hash_t const& info_hashes () const;
    -   bool v1 () const;
    +   sha1_hash info_hash () const noexcept;
        bool v2 () const;
    +   bool v1 () const;
        int num_files () const;
        std::vector<file_slice> map_block (piece_index_t const piece
           , std::int64_t offset, int size) const;
    @@ -268,22 +270,22 @@ 

    torrent_info

    void free_piece_layers (); };
    -[report issue]
    +[report issue]

    torrent_info()

    -torrent_info (std::string const& filename, load_torrent_limits const& cfg);
    -torrent_info (char const* buffer, int size, error_code& ec);
    -torrent_info (std::string const& filename, error_code& ec);
    -torrent_info (torrent_info const& t);
    -torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    -torrent_info (bdecode_node const& torrent_file, error_code& ec);
    -torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
     explicit torrent_info (info_hash_t const& info_hash);
     torrent_info (char const* buffer, int size);
    -explicit torrent_info (span<char const> buffer, from_span_t);
    -explicit torrent_info (std::string const& filename);
     torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
    +torrent_info (char const* buffer, int size, error_code& ec);
    +torrent_info (std::string const& filename, error_code& ec);
    +torrent_info (std::string const& filename, load_torrent_limits const& cfg);
    +explicit torrent_info (std::string const& filename);
    +torrent_info (bdecode_node const& torrent_file, error_code& ec);
     explicit torrent_info (bdecode_node const& torrent_file);
    +torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    +explicit torrent_info (span<char const> buffer, from_span_t);
    +torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    +torrent_info (torrent_info const& t);
     

    The constructor that takes an info-hash will initialize the info-hash to the given value, but leave all other fields empty. This is used @@ -314,16 +316,16 @@

    torrent_info()

    string literals. There is an object in the libtorrent namespace of this type called from_span.

    [report issue]
    -
    +

    ~torrent_info()

     ~torrent_info ();
     

    frees all storage associated with this torrent_info object

    - -[report issue]
    -
    -

    files() orig_files()

    + +[report issue]
    +
    +

    orig_files() files()

     file_storage const& orig_files () const;
     file_storage const& files () const;
    @@ -378,17 +380,17 @@ 

    remap_files()

    and sizes of the files in the torrent.

    The new specified file_storage must have the exact same size as the current one.

    + - -[report issue]
    -
    -

    trackers() add_tracker() clear_trackers()

    +[report issue]
    +
    +

    clear_trackers() trackers() add_tracker()

    -void add_tracker (std::string const& url, int tier = 0);
     void add_tracker (std::string const& url, int tier
           , announce_entry::tracker_source source);
    -void clear_trackers ();
    +void add_tracker (std::string const& url, int tier = 0);
     std::vector<announce_entry> const& trackers () const;
    +void clear_trackers ();
     

    add_tracker() adds a tracker to the announce-list. The tier determines the order in which the trackers are to be tried. @@ -413,21 +415,21 @@

    similar_torrents() collections()

    "collections" keys in the .torrent file. Both info-hashes and collections from within the info-dict and from outside of it are included.

    - - -[report issue]
    -
    -

    add_http_seed() set_web_seeds() web_seeds() add_url_seed()

    + + +[report issue]
    +
    +

    set_web_seeds() add_url_seed() add_http_seed() web_seeds()

    -void add_url_seed (std::string const& url
    -      , std::string const& ext_auth = std::string()
    -      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
     void add_http_seed (std::string const& url
           , std::string const& extern_auth = std::string()
           , web_seed_entry::headers_t const& extra_headers = web_seed_entry::headers_t());
    -void set_web_seeds (std::vector<web_seed_entry> seeds);
     std::vector<web_seed_entry> const& web_seeds () const;
    +void set_web_seeds (std::vector<web_seed_entry> seeds);
    +void add_url_seed (std::string const& url
    +      , std::string const& ext_auth = std::string()
    +      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
     

    web_seeds() returns all url seeds and http seeds in the torrent. Each entry is a web_seed_entry and may refer to either a url seed @@ -455,13 +457,13 @@

    total_size()

    size (modulo the last piece possibly being smaller). With pad files, the total size will be larger than the sum of all (regular) file sizes.

    - -[report issue]
    -
    -

    piece_length() num_pieces()

    + +[report issue]
    +
    +

    num_pieces() piece_length()

    -int num_pieces () const;
     int piece_length () const;
    +int num_pieces () const;
     

    piece_length() and num_pieces() returns the number of byte for each piece and the total number of pieces, respectively. The @@ -470,15 +472,23 @@

    piece_length() num_pieces()

    exact size of that piece. It will always be the same as piece_length() except in the case of the last piece, which may be smaller.

    - +[report issue]
    +
    +

    blocks_per_piece()

    +
    +int blocks_per_piece () const;
    +
    +

    returns the number of blocks there are in the typical piece. There +may be fewer in the last piece)

    -[report issue]
    -
    -

    last_piece() end_piece() piece_range()

    + +[report issue]
    +
    +

    end_piece() piece_range() last_piece()

    -piece_index_t last_piece () const;
     index_range<piece_index_t> piece_range () const;
     piece_index_t end_piece () const;
    +piece_index_t last_piece () const;
     

    last_piece() returns the index to the last piece in the torrent and end_piece() returns the index to the one-past-end piece in the @@ -486,13 +496,13 @@

    last_piece() end_piece() piece_range()

    piece_range() returns an implementation-defined type that can be used as the container in a range-for loop. Where the values are the indices of all pieces in the file_storage.

    - -[report issue]
    -
    -

    info_hash() info_hashes()

    + +[report issue]
    +
    +

    info_hashes() info_hash()

    -sha1_hash info_hash () const noexcept;
     info_hash_t const& info_hashes () const;
    +sha1_hash info_hash () const noexcept;
     

    returns the info-hash of the torrent. For BitTorrent v2 support, use info_hashes() to get an object that may hold both a v1 and v2 @@ -502,8 +512,8 @@

    info_hash() info_hashes()

    v2() v1()

    -bool v1 () const;
     bool v2 () const;
    +bool v1 () const;
     

    returns whether this torrent has v1 and/or v2 metadata, respectively. Hybrid torrents have both. These are shortcuts for diff --git a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Status.html b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Status.html index 929af98f..9470dbe9 100644 --- a/3rd/libtorrent-rasterbar/docs/reference-Torrent_Status.html +++ b/3rd/libtorrent-rasterbar/docs/reference-Torrent_Status.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,16 +25,16 @@ Version: -2.0.8 +2.0.9

    home

    Table of contents

    need_save_resume
    -
    if this flag is set (which it is by default) the torrent will be -considered needing to save its resume data immediately as it's -added. New torrents that don't have any resume data should do that. -This flag is cleared by a successful call to save_resume_data() +

    if this flag is set (which it is by default) the torrent will be +considered needing to save its resume data immediately, in the +category if_metadata_changed. See resume_data_flags_t and +save_resume_data() for details.

    +

    This flag is cleared by a successful call to save_resume_data() This flag is not saved by write_resume_data(), since it represents an -ephemeral state of a running torrent.

    +ephemeral state of a running torrent.

    +
    disable_dht
    @@ -1984,6 +2017,19 @@

    torrent_flags_t

    unless this flag is set, in which case they will be set to 0 (dont_download).
    +
    +
    i2p_torrent
    +
    this flag makes the torrent be considered an "i2p torrent" for purposes +of the allow_i2p_mixed setting. When mixing regular peers and i2p peers +is disabled, i2p torrents won't add normal peers to its peer list. +Note that non i2p torrents may still allow i2p peers (on the off-chance +that a tracker return them and the session is configured with a SAM +connection). +This flag is set automatically when adding a torrent that has at least +one tracker whose hostname ends with .i2p. +It's also set by parse_magnet_uri() if the tracker list contains such +URL.
    +
    all
    all torrent flags combined. Can conveniently be used when creating masks @@ -2075,9 +2121,9 @@

    peer_class_type_filter

    }; }; - -[report issue]
    -

    remove() add()

    + +[report issue]
    +

    add() remove()

     void remove (socket_type_t const st, peer_class_t const peer_class);
     void add (socket_type_t const st, peer_class_t const peer_class);
    @@ -2106,7 +2152,7 @@ 

    apply()

    peer classes after the rules have been applied, based on the socket type argument (st).

    [report issue]
    -
    +

    enum socket_type_t

    Declared in "libtorrent/peer_class_type_filter.hpp"

    @@ -2261,23 +2307,23 @@

    peer_connection_handle

    peer_plugin const* find_plugin (string_view type) const; bool is_seed () const; bool upload_only () const; - bool has_piece (piece_index_t i) const; peer_id const& pid () const; - bool is_interesting () const; + bool has_piece (piece_index_t i) const; bool is_choked () const; + bool is_interesting () const; bool is_peer_interested () const; bool has_peer_choked () const; - void maybe_unchoke_this_peer (); void choke_this_peer (); + void maybe_unchoke_this_peer (); void get_peer_info (peer_info& p) const; torrent_handle associated_torrent () const; tcp::endpoint const& remote () const; tcp::endpointlocal_endpoint () const; - bool is_disconnecting () const; - bool is_connecting () const; void disconnect (error_code const& ec, operation_t op , disconnect_severity_t = peer_connection_interface::normal); bool is_outgoing () const; + bool is_disconnecting () const; + bool is_connecting () const; bool ignore_unchoke_slots () const; bool on_local_network () const; bool failed () const; @@ -2290,8 +2336,8 @@

    peer_connection_handle

    void send_buffer (char const* begin, int size); std::time_t last_seen_complete () const; time_point time_of_last_unchoke () const; - bool operator!= (peer_connection_handle const& o) const; bool operator< (peer_connection_handle const& o) const; + bool operator!= (peer_connection_handle const& o) const; bool operator== (peer_connection_handle const& o) const; std::shared_ptr<peer_connection> native_handle () const; }; @@ -2307,11 +2353,11 @@

    bt_peer_connection_handle

    struct bt_peer_connection_handle : peer_connection_handle { explicit bt_peer_connection_handle (peer_connection_handle pc); - bool support_extensions () const; bool packet_finished () const; + bool support_extensions () const; bool supports_encryption () const; - void switch_recv_crypto (std::shared_ptr<crypto_plugin> crypto); void switch_send_crypto (std::shared_ptr<crypto_plugin> crypto); + void switch_recv_crypto (std::shared_ptr<crypto_plugin> crypto); std::shared_ptr<bt_peer_connection> native_handle () const; }; @@ -2479,8 +2525,8 @@

    torrent_plugin

    virtual void on_piece_failed (piece_index_t); virtual void on_piece_pass (piece_index_t); virtual void tick (); - virtual bool on_pause (); virtual bool on_resume (); + virtual bool on_pause (); virtual void on_files_checked (); virtual void on_state (torrent_status::state_t); virtual void on_add_peer (tcp::endpoint const&, @@ -2507,10 +2553,10 @@

    new_connection()

    keep a shared_ptr to your own peer_plugin. If you want to keep references to it, use weak_ptr.

    If this function throws an exception, the connection will be closed.

    - -[report issue] -
    -

    on_piece_pass() on_piece_failed()

    + +[report issue]
    +
    +

    on_piece_failed() on_piece_pass()

     virtual void on_piece_failed (piece_index_t);
     virtual void on_piece_pass (piece_index_t);
    @@ -2532,8 +2578,8 @@ 

    tick()

    on_pause() on_resume()

    -virtual bool on_pause ();
     virtual bool on_resume ();
    +virtual bool on_pause ();
     

    These hooks are called when the torrent is paused and resumed respectively. The return value indicates if the event was handled. A return value of @@ -2606,35 +2652,35 @@

    peer_plugin

    virtual void on_connected (); virtual bool on_handshake (span<char const>); virtual bool on_extension_handshake (bdecode_node const&); - virtual bool on_have (piece_index_t); virtual bool on_dont_have (piece_index_t); - virtual bool on_unchoke (); + virtual bool on_not_interested (); virtual bool on_request (peer_request const&); - virtual bool on_have_none (); virtual bool on_choke (); virtual bool on_interested (); - virtual bool on_have_all (); - virtual bool on_not_interested (); virtual bool on_allowed_fast (piece_index_t); + virtual bool on_have_all (); + virtual bool on_have (piece_index_t); + virtual bool on_unchoke (); virtual bool on_bitfield (bitfield const& /*bitfield*/); + virtual bool on_have_none (); virtual bool on_piece (peer_request const& /*piece*/ , span<char const> /*buf*/); + virtual bool on_reject (peer_request const&); virtual bool on_suggest (piece_index_t); virtual bool on_cancel (peer_request const&); - virtual bool on_reject (peer_request const&); - virtual void sent_reject_request (peer_request const&); virtual void sent_request (peer_request const&); virtual void sent_suggest (piece_index_t); - virtual void sent_have_all (); - virtual void sent_have_none (); + virtual void sent_reject_request (peer_request const&); virtual void sent_choke (); - virtual void sent_cancel (peer_request const&); + virtual void sent_have_none (); virtual void sent_allow_fast (piece_index_t); + virtual void sent_have_all (); + virtual void sent_cancel (peer_request const&); virtual void sent_piece (peer_request const&); - virtual void sent_interested (); - virtual void sent_unchoke (); - virtual void sent_not_interested (); virtual void sent_have (piece_index_t); + virtual void sent_not_interested (); + virtual void sent_unchoke (); + virtual void sent_interested (); virtual void sent_payload (int /* bytes */); virtual bool can_disconnect (error_code const& /*ec*/); virtual bool on_extended (int /*length*/, int /*msg*/, @@ -2700,31 +2746,31 @@

    on_extension_handshake()

    supported by this peer. It will result in this peer_plugin being removed from the peer_connection and destructed. this is not called for web seeds

    - + - + + + - - - -[report issue]
    -
    -

    on_dont_have() on_interested() on_have_all() on_have_none() on_allowed_fast() on_choke() on_bitfield() on_have() on_unchoke() on_not_interested() on_request()

    + +[report issue]
    +
    +

    on_not_interested() on_interested() on_have_all() on_dont_have() on_bitfield() on_request() on_allowed_fast() on_choke() on_have() on_have_none() on_unchoke()

    -virtual bool on_have (piece_index_t);
     virtual bool on_dont_have (piece_index_t);
    -virtual bool on_unchoke ();
    +virtual bool on_not_interested ();
     virtual bool on_request (peer_request const&);
    -virtual bool on_have_none ();
     virtual bool on_choke ();
     virtual bool on_interested ();
    -virtual bool on_have_all ();
    -virtual bool on_not_interested ();
     virtual bool on_allowed_fast (piece_index_t);
    +virtual bool on_have_all ();
    +virtual bool on_have (piece_index_t);
    +virtual bool on_unchoke ();
     virtual bool on_bitfield (bitfield const& /*bitfield*/);
    +virtual bool on_have_none ();
     

    returning true from any of the message handlers indicates that the plugin has handled the message. @@ -2744,19 +2790,19 @@

    on_piece()

    in the length member of the piece parameter. returns true to indicate that the piece is handled and the rest of the logic should be ignored.

    - - + + -[report issue]
    -
    -

    sent_unchoke() sent_not_interested() sent_piece() sent_interested() sent_have()

    +[report issue]
    +
    +

    sent_have() sent_piece() sent_not_interested() sent_interested() sent_unchoke()

     virtual void sent_piece (peer_request const&);
    -virtual void sent_interested ();
    -virtual void sent_unchoke ();
    -virtual void sent_not_interested ();
     virtual void sent_have (piece_index_t);
    +virtual void sent_not_interested ();
    +virtual void sent_unchoke ();
    +virtual void sent_interested ();
     

    called after a choke message has been sent to the peer

    [report issue]
    @@ -2800,10 +2846,10 @@

    on_unknown_message()

    span<char const> /*body*/);

    this is not called for web seeds

    - -[report issue]
    -
    -

    on_piece_pass() on_piece_failed()

    + +[report issue]
    +
    +

    on_piece_failed() on_piece_pass()

     virtual void on_piece_failed (piece_index_t);
     virtual void on_piece_pass (piece_index_t);
    @@ -2811,7 +2857,7 @@ 

    on_piece_pass() on_piece_failed()

    called when a piece that this peer participated in either fails or passes the hash_check

    [report issue]
    -
    +

    tick()

     virtual void tick ();
    @@ -2834,8 +2880,8 @@ 

    crypto_plugin

     struct crypto_plugin
     {
    -   virtual void set_outgoing_key (span<char const> key) = 0;
        virtual void set_incoming_key (span<char const> key) = 0;
    +   virtual void set_outgoing_key (span<char const> key) = 0;
        encrypt (span<span<char>> /*send_vec*/) = 0;
        virtual std::tuple<int, int, int> decrypt (span<span<char>> /*receive_vec*/) = 0;
     };
    @@ -2910,32 +2956,32 @@ 

    client_data_t

    client_data_t () = default; explicit client_data_t (T* v); client_data_t& operator= (T* v); - T* get () const; explicit operator T () const; + T* get () const; client_data_t& operator= (void const*) = delete; - operator void const* () const = delete; - operator void* () const = delete; client_data_t& operator= (void*) = delete; + operator void* () const = delete; + operator void const* () const = delete; template <typename T, typename U = typename std::enable_if<std::is_pointer<T>::value>::type> };
    -[report issue]
    +[report issue]

    client_data_t()

     client_data_t () = default;
     

    construct a nullptr client data

    - -[report issue]
    -
    -

    operator=() const*() void*()

    + +[report issue]
    +
    +

    operator=() void*() const*()

     client_data_t& operator= (void const*) = delete;
    -operator void const* () const = delete;
    -operator void* () const = delete;
     client_data_t& operator= (void*) = delete;
    +operator void* () const = delete;
    +operator void const* () const = delete;
     

    we don't allow type-unsafe operations

    [report issue]
    @@ -3257,7 +3303,9 @@

    add_torrent_params

    [report issue]
    last_download last_upload
    the posix time of the last time payload was received or sent for this -torrent, respectively.
    +torrent, respectively. A value of 0 means we don't know when we last +uploaded or downloaded, or we have never uploaded or downloaded any +payload for this torrent.
    [report issue]
    @@ -3354,11 +3402,11 @@

    announce_entry

     struct announce_entry
     {
    +   ~announce_entry ();
    +   announce_entry& operator= (announce_entry const&) &;
        explicit announce_entry (string_view u);
        announce_entry (announce_entry const&);
        announce_entry ();
    -   announce_entry& operator= (announce_entry const&) &;
    -   ~announce_entry ();
     
        enum tracker_source
        {
    @@ -3382,11 +3430,11 @@ 

    announce_entry

    [report issue]

    announce_entry() operator=() ~announce_entry()

    +~announce_entry ();
    +announce_entry& operator= (announce_entry const&) &;
     explicit announce_entry (string_view u);
     announce_entry (announce_entry const&);
     announce_entry ();
    -announce_entry& operator= (announce_entry const&) &;
    -~announce_entry ();
     

    constructs a tracker announce entry with u as the URL.

    [report issue]
    @@ -3736,13 +3784,13 @@

    settings_interface

     struct settings_interface
     {
    -   virtual void set_bool (int name, bool val) = 0;
    -   virtual void set_int (int name, int val) = 0;
        virtual bool has_val (int name) const = 0;
    +   virtual void set_int (int name, int val) = 0;
    +   virtual void set_bool (int name, bool val) = 0;
        virtual void set_str (int name, std::string val) = 0;
        virtual bool get_bool (int name) const = 0;
    -   virtual std::string const& get_str (int name) const = 0;
        virtual int get_int (int name) const = 0;
    +   virtual std::string const& get_str (int name) const = 0;
     };
     
    [report issue]
    @@ -3862,7 +3910,7 @@

    disk_interface

    static constexpr disk_job_flags_t flush_piece = 7_bit; };
    -[report issue]
    +[report issue]

    new_torrent()

     virtual storage_holder new_torrent (storage_params const& p
    @@ -4074,7 +4122,7 @@ 

    get_status()

    query the currently open files, and which modes those files are open in.

    [report issue]
    -
    +

    abort()

     virtual void abort (bool wait) = 0;
    @@ -4152,9 +4200,9 @@ 

    storage_holder

     struct storage_holder
     {
    -   storage_holder (storage_index_t idx, disk_interface& disk_io);
    -   ~storage_holder ();
        storage_holder () = default;
    +   ~storage_holder ();
    +   storage_holder (storage_index_t idx, disk_interface& disk_io);
        explicit operator bool () const;
        operator storage_index_t () const;
        void reset ();
    @@ -4188,8 +4236,8 @@ 

    disk_buffer_holder

     struct disk_buffer_holder
     {
    -   disk_buffer_holder& operator= (disk_buffer_holder&&) & noexcept;
        disk_buffer_holder (disk_buffer_holder&&) noexcept;
    +   disk_buffer_holder& operator= (disk_buffer_holder&&) & noexcept;
        disk_buffer_holder& operator= (disk_buffer_holder const&) = delete;
        disk_buffer_holder (disk_buffer_holder const&) = delete;
        disk_buffer_holder (buffer_allocator_interface& alloc
    @@ -4204,7 +4252,7 @@ 

    disk_buffer_holder

    std::ptrdiff_t size () const; };
    -[report issue]
    +[report issue]

    disk_buffer_holder()

     disk_buffer_holder (buffer_allocator_interface& alloc
    @@ -4214,14 +4262,14 @@ 

    disk_buffer_holder()

    using a disk buffer pool directly (there's only one disk_buffer_pool per session)

    [report issue]
    -
    +

    disk_buffer_holder()

     disk_buffer_holder () noexcept = default;
     

    default construct a holder that does not own any buffer

    [report issue]
    -
    +

    ~disk_buffer_holder()

     ~disk_buffer_holder ();
    @@ -4594,7 +4642,10 @@ 

    settings_pack

    sets the i2p SAM bridge to connect to. set the port with the -i2p_port setting.

    +i2p_port setting. Unless this is set, i2p torrents are not +supported. This setting is separate from the other proxy settings +since i2p torrents and their peers are orthogonal. You can have +i2p peers as well as regular peers via a proxy.

    @@ -4610,7 +4661,7 @@

    settings_pack

    - +
    peer_fingerprint string-LT2080--LT2090-
    @@ -7160,6 +7211,10 @@

    settings_pack

    default (i.e. don't change the buffer sizes). The socket buffer sizes are changed using setsockopt() with SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER.

    +

    Note that uTP peers share a single UDP socket buffer for each of the +listen_interfaces, along with DHT and UDP tracker traffic. +If the buffer size is too small for the combined traffic through the +socket, packets may be dropped.

    @@ -8762,22 +8817,63 @@

    settings_pack

    when using mmap_disk_io, files smaller than this number of blocks will not be memory mapped, but will use normal pread/pwrite operations. This file size limit is specified in 16 kiB blocks.

    + + + +
    +++++ + + + + + + + + + + + + + + + + + + + + + + + + +
    nametypedefault
    i2p_inbound_quantityint3
    i2p_outbound_quantityint3
    i2p_inbound_lengthint3
    i2p_outbound_lengthint3
    +

    Configures the SAM session +quantity of I2P inbound and outbound tunnels [1..16]. +number of hops for I2P inbound and outbound tunnels [0..7] +Changing these will not trigger a reconnect to the SAM bridge, +they will take effect the next time the SAM connection is +re-established (by restarting or changing i2p_hostname or +i2p_port).

     struct settings_pack final : settings_interface
     {
        friend  void apply_pack_impl (settings_pack const*
           , aux::session_settings_single_thread&
           , std::vector<void(aux::session_impl::*)()>*);
    +   void set_str (int name, std::string val) override;
        void set_int (int name, flags::bitfield_flag<Type, Tag> const val);
        void set_int (int name, int val) override;
    -   void set_str (int name, std::string val) override;
        void set_bool (int name, bool val) override;
        bool has_val (int name) const override;
        void clear ();
        void clear (int name);
    -   std::string const& get_str (int name) const override;
    -   int get_int (int name) const override;
        bool get_bool (int name) const override;
    +   int get_int (int name) const override;
    +   std::string const& get_str (int name) const override;
        void for_each (Fun&& f) const;
     
        enum type_bases
    @@ -8852,18 +8948,17 @@ 

    settings_pack

    socks5_pw, http, http_pw, - i2p_proxy, }; };
    - -[report issue]
    -

    set_int() set_str() set_bool()

    + +[report issue]
    +

    set_int() set_bool() set_str()

    +void set_str (int name, std::string val) override;
     void set_int (int name, flags::bitfield_flag<Type, Tag> const val);
     void set_int (int name, int val) override;
    -void set_str (int name, std::string val) override;
     void set_bool (int name, bool val) override;
     

    set a configuration option in the settings_pack. name is one of @@ -8886,21 +8981,21 @@

    clear()

    clear the settings pack from all settings

    [report issue]
    -
    +

    clear()

     void clear (int name);
     

    clear a specific setting from the pack

    - + -[report issue]
    -
    -

    get_str() get_int() get_bool()

    +[report issue]
    +
    +

    get_bool() get_int() get_str()

    -std::string const& get_str (int name) const override;
    -int get_int (int name) const override;
     bool get_bool (int name) const override;
    +int get_int (int name) const override;
    +std::string const& get_str (int name) const override;
     

    queries the current configuration option from the settings_pack. name is one of the enumeration values from string_types, int_types @@ -9265,17 +9360,13 @@

    enum proxy_type_t

    The server is assumed to be an HTTP proxy that requires user authorization. The username and password will be sent to the proxy. -i2p_proxy -6 -route through a i2p SAM proxy - - -[report issue]
    + +[report issue]
    -
    -

    setting_by_name() name_for_setting()

    +
    +

    name_for_setting() setting_by_name()

    Declared in "libtorrent/settings_pack.hpp"

     int setting_by_name (string_view name);
    @@ -9297,8 +9388,8 @@ 

    default_settings()

    high_performance_seed() min_memory_usage()

    Declared in "libtorrent/session.hpp"

    -settings_pack min_memory_usage ();
     settings_pack high_performance_seed ();
    +settings_pack min_memory_usage ();
     

    The default values of the session settings are set for a regular bittorrent client running on a desktop system. There are functions that @@ -9441,10 +9532,6 @@

    file_storage

    { bool is_valid () const; void reserve (int num_files); - void add_file (std::string const& path, std::int64_t file_size - , file_flags_t file_flags = {} - , std::time_t mtime = 0, string_view symlink_path = string_view() - , char const* root_hash = nullptr); void add_file_borrow (string_view filename , std::string const& path, std::int64_t file_size , file_flags_t file_flags = {}, char const* filehash = nullptr @@ -9455,6 +9542,10 @@

    file_storage

    , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); + void add_file (std::string const& path, std::int64_t file_size + , file_flags_t file_flags = {} + , std::time_t mtime = 0, string_view symlink_path = string_view() + , char const* root_hash = nullptr); void add_file (error_code& ec, std::string const& path, std::int64_t file_size , file_flags_t file_flags = {} , std::time_t mtime = 0, string_view symlink_path = string_view() @@ -9467,41 +9558,42 @@

    file_storage

    file_index_t end_file () const noexcept; index_range<file_index_t> file_range () const noexcept; std::int64_t total_size () const; - void set_num_pieces (int n); int num_pieces () const; + void set_num_pieces (int n); piece_index_t end_piece () const; piece_index_t last_piece () const; index_range<piece_index_t> piece_range () const noexcept; - int piece_length () const; void set_piece_length (int l); + int piece_length () const; int piece_size (piece_index_t index) const; int piece_size2 (piece_index_t index) const; int blocks_in_piece2 (piece_index_t index) const; + int blocks_per_piece () const; std::string const& name () const; void set_name (std::string const& n); void swap (file_storage& ti) noexcept; void canonicalize (); - std::int64_t file_offset (file_index_t index) const; - std::time_t mtime (file_index_t index) const; char const* root_ptr (file_index_t const index) const; - bool pad_file_at (file_index_t index) const; + sha1_hash hash (file_index_t index) const; std::string symlink (file_index_t index) const; + std::string file_path (file_index_t index, std::string const& save_path = "") const; + bool pad_file_at (file_index_t index) const; + std::time_t mtime (file_index_t index) const; + string_view file_name (file_index_t index) const; + std::int64_t file_offset (file_index_t index) const; sha256_hash root (file_index_t index) const; std::int64_t file_size (file_index_t index) const; - string_view file_name (file_index_t index) const; - sha1_hash hash (file_index_t index) const; - std::string file_path (file_index_t index, std::string const& save_path = "") const; + int file_num_pieces (file_index_t index) const; int file_num_blocks (file_index_t index) const; index_range<piece_index_t::diff_type> file_piece_range (file_index_t) const; - int file_num_pieces (file_index_t index) const; - int file_first_block_node (file_index_t index) const; int file_first_piece_node (file_index_t index) const; + int file_first_block_node (file_index_t index) const; std::uint32_t file_path_hash (file_index_t index, std::string const& save_path) const; void all_path_hashes (std::unordered_set<std::uint32_t>& table) const; file_flags_t file_flags (file_index_t index) const; bool file_absolute_path (file_index_t index) const; - file_index_t file_index_at_piece (piece_index_t piece) const; file_index_t file_index_at_offset (std::int64_t offset) const; + file_index_t file_index_at_piece (piece_index_t piece) const; file_index_t file_index_for_root (sha256_hash const& root_hash) const; piece_index_t piece_index_at_file (file_index_t f) const; void sanitize_symlinks (); @@ -9531,15 +9623,11 @@

    reserve()

    allocates space for num_files in the internal file list. This can be used to avoid reallocating the internal file list when the number of files to be added is known up-front.

    - -[report issue]
    -
    -

    add_file_borrow() add_file()

    + +[report issue]
    +
    +

    add_file() add_file_borrow()

    -void add_file (std::string const& path, std::int64_t file_size
    -      , file_flags_t file_flags = {}
    -      , std::time_t mtime = 0, string_view symlink_path = string_view()
    -      , char const* root_hash = nullptr);
     void add_file_borrow (string_view filename
           , std::string const& path, std::int64_t file_size
           , file_flags_t file_flags = {}, char const* filehash = nullptr
    @@ -9550,6 +9638,10 @@ 

    add_file_borrow() add_file()

    , file_flags_t file_flags = {}, char const* filehash = nullptr , std::int64_t mtime = 0, string_view symlink_path = string_view() , char const* root_hash = nullptr); +void add_file (std::string const& path, std::int64_t file_size + , file_flags_t file_flags = {} + , std::time_t mtime = 0, string_view symlink_path = string_view() + , char const* root_hash = nullptr); void add_file (error_code& ec, std::string const& path, std::int64_t file_size , file_flags_t file_flags = {} , std::time_t mtime = 0, string_view symlink_path = string_view() @@ -9659,13 +9751,13 @@

    total_size()

    std::int64_t total_size () const;

    returns the total number of bytes all the files in this torrent spans

    - -[report issue]
    -
    -

    set_num_pieces() num_pieces()

    + +[report issue]
    +
    +

    num_pieces() set_num_pieces()

    -void set_num_pieces (int n);
     int num_pieces () const;
    +void set_num_pieces (int n);
     

    set and get the number of pieces in the torrent

    [report issue]
    @@ -9698,8 +9790,8 @@

    piece_range()

    set_piece_length() piece_length()

    -int piece_length () const;
     void set_piece_length (int l);
    +int piece_length () const;
     

    set and get the size of each piece in this torrent. It must be a power of two and at least 16 kiB.

    @@ -9728,10 +9820,18 @@

    blocks_in_piece2()

    int blocks_in_piece2 (piece_index_t index) const;

    returns the number of blocks in the specified piece, for v2 torrents.

    - -[report issue]
    -
    -

    set_name() name()

    +[report issue]
    +
    +

    blocks_per_piece()

    +
    +int blocks_per_piece () const;
    +
    +

    returns the number of blocks there are in the typical piece. There +may be fewer in the last piece)

    + +[report issue]
    +
    +

    name() set_name()

     std::string const& name () const;
     void set_name (std::string const& n);
    @@ -9739,7 +9839,7 @@ 

    set_name() name()

    set and get the name of this torrent. For multi-file torrents, this is also the name of the root directory all the files are stored in.

    [report issue]
    -
    +

    swap()

     void swap (file_storage& ti) noexcept;
    @@ -9753,29 +9853,29 @@ 

    canonicalize()

    arrange files and padding to match the canonical form required by BEP 52

    - - - - + - + + + - -[report issue]
    - + -
    -

    file_num_blocks() file_num_pieces() file_piece_range()

    + +[report issue]
    +
    +

    file_num_blocks() file_piece_range() file_num_pieces()

    +int file_num_pieces (file_index_t index) const;
     int file_num_blocks (file_index_t index) const;
     index_range<piece_index_t::diff_type> file_piece_range (file_index_t) const;
    -int file_num_pieces (file_index_t index) const;
     

    Returns the number of pieces or blocks the file at index spans, under the assumption that the file is aligned to the start of a piece. @@ -9822,8 +9922,8 @@

    file_num_blocks() file_num_pieces() file_piece_range()

    file_first_piece_node() file_first_block_node()

    -int file_first_block_node (file_index_t index) const;
     int file_first_piece_node (file_index_t index) const;
    +int file_first_block_node (file_index_t index) const;
     

    index of first piece node in the merkle tree

    [report issue]
    @@ -9867,8 +9967,8 @@

    file_absolute_path()

    file_index_at_offset() file_index_at_piece()

    -file_index_t file_index_at_piece (piece_index_t piece) const;
     file_index_t file_index_at_offset (std::int64_t offset) const;
    +file_index_t file_index_at_piece (piece_index_t piece) const;
     

    returns the index of the file at the given offset in the torrent

    [report issue]
    @@ -10090,27 +10190,27 @@

    session_handle

    { bool is_valid () const; session_params session_state (save_state_flags_t flags = save_state_flags_t::all()) const; - void refresh_torrent_status (std::vector<torrent_status>* ret - , status_flags_t flags = {}) const; std::vector<torrent_status> get_torrent_status ( std::function<bool(torrent_status const&)> const& pred , status_flags_t flags = {}) const; + void refresh_torrent_status (std::vector<torrent_status>* ret + , status_flags_t flags = {}) const; void post_torrent_updates (status_flags_t flags = status_flags_t::all()); void post_session_stats (); void post_dht_stats (); - void set_dht_state (dht::dht_state&& st); void set_dht_state (dht::dht_state const& st); - std::vector<torrent_handle> get_torrents () const; + void set_dht_state (dht::dht_state&& st); torrent_handle find_torrent (sha1_hash const& info_hash) const; + std::vector<torrent_handle> get_torrents () const; torrent_handle add_torrent (add_torrent_params const& params, error_code& ec); - torrent_handle add_torrent (add_torrent_params&& params); - torrent_handle add_torrent (add_torrent_params&& params, error_code& ec); void async_add_torrent (add_torrent_params&& params); - torrent_handle add_torrent (add_torrent_params const& params); void async_add_torrent (add_torrent_params const& params); + torrent_handle add_torrent (add_torrent_params&& params, error_code& ec); + torrent_handle add_torrent (add_torrent_params&& params); + torrent_handle add_torrent (add_torrent_params const& params); + void resume (); bool is_paused () const; void pause (); - void resume (); bool is_dht_running () const; void set_dht_storage (dht::dht_storage_constructor_type sc); void add_dht_node (std::pair<std::string, int> const& node); @@ -10127,15 +10227,15 @@

    session_handle

    void dht_live_nodes (sha1_hash const& nid); void dht_sample_infohashes (udp::endpoint const& ep, sha1_hash const& target); void dht_direct_request (udp::endpoint const& ep, entry const& e, client_data_t userdata = {}); - void add_extension (std::shared_ptr<plugin> ext); void add_extension (std::function<std::shared_ptr<torrent_plugin>( torrent_handle const&, client_data_t)> ext); + void add_extension (std::shared_ptr<plugin> ext); void set_ip_filter (ip_filter f); ip_filter get_ip_filter () const; void set_port_filter (port_filter const& f); + bool is_listening () const; unsigned short listen_port () const; unsigned short ssl_listen_port () const; - bool is_listening () const; ip_filter get_peer_class_filter () const; void set_peer_class_filter (ip_filter const& f); peer_class_type_filter get_peer_class_type_filter () const; @@ -10148,11 +10248,11 @@

    session_handle

    settings_pack get_settings () const; void apply_settings (settings_pack&&); void apply_settings (settings_pack const&); - void set_alert_notify (std::function<void()> const& fun); - void pop_alerts (std::vector<alert*>* alerts); alert* wait_for_alert (time_duration max_wait); - void delete_port_mapping (port_mapping_t handle); + void pop_alerts (std::vector<alert*>* alerts); + void set_alert_notify (std::function<void()> const& fun); std::vector<port_mapping_t> add_port_mapping (portmap_protocol t, int external_port, int local_port); + void delete_port_mapping (port_mapping_t handle); void reopen_network_sockets (reopen_network_flags_t options = reopen_map_ports); std::shared_ptr<aux::session_impl> native_handle () const; @@ -10171,7 +10271,7 @@

    session_handle

    static constexpr reopen_network_flags_t reopen_map_ports = 0_bit; }; -[report issue]
    +[report issue]

    is_valid()

     bool is_valid () const;
    @@ -10192,16 +10292,16 @@ 

    session_state()

    plugin-specific state. the flags parameter can be used to only save certain parts of the session state

    - -[report issue]
    -
    -

    refresh_torrent_status() get_torrent_status()

    + +[report issue]
    +
    +

    get_torrent_status() refresh_torrent_status()

    -void refresh_torrent_status (std::vector<torrent_status>* ret
    -      , status_flags_t flags = {}) const;
     std::vector<torrent_status> get_torrent_status (
           std::function<bool(torrent_status const&)> const& pred
           , status_flags_t flags = {}) const;
    +void refresh_torrent_status (std::vector<torrent_status>* ret
    +      , status_flags_t flags = {}) const;
     

    Note

    @@ -10273,19 +10373,19 @@

    post_dht_stats()

    set_dht_state()

    -void set_dht_state (dht::dht_state&& st);
     void set_dht_state (dht::dht_state const& st);
    +void set_dht_state (dht::dht_state&& st);
     

    set the DHT state for the session. This will be taken into account the next time the DHT is started, as if it had been passed in via the session_params on startup.

    - -[report issue]
    -
    -

    get_torrents() find_torrent()

    + +[report issue]
    +
    +

    find_torrent() get_torrents()

    -std::vector<torrent_handle> get_torrents () const;
     torrent_handle find_torrent (sha1_hash const& info_hash) const;
    +std::vector<torrent_handle> get_torrents () const;
     

    find_torrent() looks for a torrent with the given info-hash. In case there is such a torrent in the session, a torrent_handle to that @@ -10295,17 +10395,17 @@

    get_torrents() find_torrent()

    not.

    get_torrents() returns a vector of torrent_handles to all the torrents currently in the session.

    - -[report issue]
    -
    -

    add_torrent() async_add_torrent()

    + +[report issue]
    +
    +

    async_add_torrent() add_torrent()

     torrent_handle add_torrent (add_torrent_params const& params, error_code& ec);
    -torrent_handle add_torrent (add_torrent_params&& params);
    -torrent_handle add_torrent (add_torrent_params&& params, error_code& ec);
     void async_add_torrent (add_torrent_params&& params);
    -torrent_handle add_torrent (add_torrent_params const& params);
     void async_add_torrent (add_torrent_params const& params);
    +torrent_handle add_torrent (add_torrent_params&& params, error_code& ec);
    +torrent_handle add_torrent (add_torrent_params&& params);
    +torrent_handle add_torrent (add_torrent_params const& params);
     

    You add torrents through the add_torrent() function where you give an object with all the parameters. The add_torrent() overloads will block @@ -10333,15 +10433,15 @@

    add_torrent() async_add_torrent()

    Special consideration has to be taken when adding hybrid torrents (i.e. torrents that are BitTorrent v2 torrents that are backwards compatible with v1). For more details, see BitTorrent v2 torrents.

    - + -[report issue]
    -
    -

    pause() is_paused() resume()

    +[report issue]
    +
    +

    resume() is_paused() pause()

    +void resume ();
     bool is_paused () const;
     void pause ();
    -void resume ();
     

    Pausing the session has the same effect as pausing every torrent in it, except that torrents will not be resumed by the auto-manage @@ -10391,7 +10491,7 @@

    dht_get_item()

    query the DHT for an immutable item at the target hash. the result is posted as a dht_immutable_item_alert.

    [report issue]
    -
    +

    dht_get_item()

     void dht_get_item (std::array<char, 32> key
    @@ -10413,7 +10513,7 @@ 

    dht_put_item()

    up again. It's just the SHA-1 hash of the bencoded form of the structure.

    [report issue]
    -
    +

    dht_put_item()

     void dht_put_item (std::array<char, 32> key
    @@ -10515,9 +10615,9 @@ 

    dht_direct_request()

    add_extension()

    -void add_extension (std::shared_ptr<plugin> ext);
     void add_extension (std::function<std::shared_ptr<torrent_plugin>(
           torrent_handle const&, client_data_t)> ext);
    +void add_extension (std::shared_ptr<plugin> ext);
     

    This function adds an extension to this session. The argument is a function object that is called with a torrent_handle and which should @@ -10553,10 +10653,10 @@

    add_extension()

    #include <libtorrent/extensions/smart_ban.hpp> ses.add_extension(&lt::create_smart_ban_plugin);
    - -[report issue]
    -
    -

    get_ip_filter() set_ip_filter()

    + +[report issue]
    +
    +

    set_ip_filter() get_ip_filter()

     void set_ip_filter (ip_filter f);
     ip_filter get_ip_filter () const;
    @@ -10578,15 +10678,15 @@ 

    set_port_filter()

    will reject making outgoing peer connections to certain remote ports. The main intention is to be able to avoid triggering certain anti-virus software by connecting to SMTP, FTP ports.

    - -[report issue]
    -
    -

    is_listening() listen_port() ssl_listen_port()

    + +[report issue]
    +
    +

    listen_port() is_listening() ssl_listen_port()

    +bool is_listening () const;
     unsigned short listen_port () const;
     unsigned short ssl_listen_port () const;
    -bool is_listening () const;
     

    is_listening() will tell you whether or not the session has successfully opened a listening port. If it hasn't, this function will @@ -10594,10 +10694,10 @@

    is_listening() listen_port() ssl_listen_port()

    settings_pack::listen_interfaces to try another interface and port to bind to.

    listen_port() returns the port we ended up listening on.

    - -[report issue]
    -
    -

    get_peer_class_filter() set_peer_class_filter()

    + +[report issue]
    +
    +

    set_peer_class_filter() get_peer_class_filter()

     ip_filter get_peer_class_filter () const;
     void set_peer_class_filter (ip_filter const& f);
    @@ -10628,10 +10728,10 @@ 

    get_peer_class_filter() set_peer_class_filter()

    representing peer classes in the peer_class_filter are 32 bits.

    The get_peer_class_filter() function returns the current filter.

    For more information, see peer classes.

    - -[report issue]
    -
    -

    get_peer_class_type_filter() set_peer_class_type_filter()

    + +[report issue]
    +
    +

    set_peer_class_type_filter() get_peer_class_type_filter()

     peer_class_type_filter get_peer_class_type_filter () const;
     void set_peer_class_type_filter (peer_class_type_filter const& f);
    @@ -10681,10 +10781,10 @@ 

    delete_peer_class()

    peer classes will be properly destructed when the session object destructs.

    For more information on peer classes, see peer classes.

    - -[report issue]
    -
    -

    get_peer_class() set_peer_class()

    + +[report issue]
    +
    +

    set_peer_class() get_peer_class()

     void set_peer_class (peer_class_t cid, peer_class_info const& pci);
     peer_class_info get_peer_class (peer_class_t cid) const;
    @@ -10701,7 +10801,7 @@ 

    get_peer_class() set_peer_class()

    account.

    For more information, see peer classes.

    [report issue]
    -
    +

    remove_torrent()

     void remove_torrent (const torrent_handle&, remove_flags_t = {});
    @@ -10747,15 +10847,15 @@ 

    apply_settings() get_settings()

    Applies the settings specified by the settings_pack s. This is an asynchronous operation that will return immediately and actually apply the settings to the main thread of libtorrent some time later.

    - + -[report issue]
    -
    -

    set_alert_notify() wait_for_alert() pop_alerts()

    +[report issue]
    +
    +

    pop_alerts() wait_for_alert() set_alert_notify()

    -void set_alert_notify (std::function<void()> const& fun);
    -void pop_alerts (std::vector<alert*>* alerts);
     alert* wait_for_alert (time_duration max_wait);
    +void pop_alerts (std::vector<alert*>* alerts);
    +void set_alert_notify (std::function<void()> const& fun);
     

    Alerts is the main mechanism for libtorrent to report errors and events. pop_alerts fills in the vector passed to it with pointers @@ -10814,8 +10914,8 @@

    set_alert_notify() wait_for_alert() pop_alerts()

    delete_port_mapping() add_port_mapping()

    -void delete_port_mapping (port_mapping_t handle);
     std::vector<port_mapping_t> add_port_mapping (portmap_protocol t, int external_port, int local_port);
    +void delete_port_mapping (port_mapping_t handle);
     

    add_port_mapping adds one or more port forwards on UPnP and/or NAT-PMP, whichever is enabled. A mapping is created for each listen socket @@ -10903,25 +11003,25 @@

    session_proxy

     struct session_proxy
     {
    -   session_proxy& operator= (session_proxy const&) &;
    -   session_proxy (session_proxy&&) noexcept;
    -   session_proxy& operator= (session_proxy&&) & noexcept;
        session_proxy (session_proxy const&);
    -   ~session_proxy ();
        session_proxy ();
    +   ~session_proxy ();
    +   session_proxy& operator= (session_proxy&&) & noexcept;
    +   session_proxy (session_proxy&&) noexcept;
    +   session_proxy& operator= (session_proxy const&) &;
     };
     
    + - -[report issue]
    -

    operator=() session_proxy() ~session_proxy()

    +[report issue]
    +

    ~session_proxy() operator=() session_proxy()

    -session_proxy& operator= (session_proxy const&) &;
    -session_proxy (session_proxy&&) noexcept;
    -session_proxy& operator= (session_proxy&&) & noexcept;
     session_proxy (session_proxy const&);
    -~session_proxy ();
     session_proxy ();
    +~session_proxy ();
    +session_proxy& operator= (session_proxy&&) & noexcept;
    +session_proxy (session_proxy&&) noexcept;
    +session_proxy& operator= (session_proxy const&) &;
     

    default constructor, does not refer to any session implementation object.

    @@ -10943,27 +11043,27 @@

    session

     struct session : session_handle
     {
    -   session (session_params&& params, session_flags_t flags);
    -   session ();
    +   explicit session (session_params const& params);
        explicit session (session_params&& params);
    +   session ();
        session (session_params const& params, session_flags_t flags);
    -   explicit session (session_params const& params);
    -   session (session_params const& params, io_context& ios, session_flags_t);
    +   session (session_params&& params, session_flags_t flags);
    +   session (session_params&& params, io_context& ios);
        session (session_params&& params, io_context& ios, session_flags_t);
        session (session_params const& params, io_context& ios);
    -   session (session_params&& params, io_context& ios);
    +   session (session_params const& params, io_context& ios, session_flags_t);
        ~session ();
        session_proxy abort ();
     };
     
    -[report issue]
    +[report issue]

    session()

    -session (session_params&& params, session_flags_t flags);
    -session ();
    +explicit session (session_params const& params);
     explicit session (session_params&& params);
    +session ();
     session (session_params const& params, session_flags_t flags);
    -explicit session (session_params const& params);
    +session (session_params&& params, session_flags_t flags);
     

    Constructs the session objects which acts as the container of torrents. In order to avoid a race condition between starting the session and @@ -10974,13 +11074,13 @@

    session()

    add_default_plugins do not have an affect on constructors that take a session_params object. It already contains the plugins to use.

    [report issue]
    -
    +

    session()

    -session (session_params const& params, io_context& ios, session_flags_t);
    +session (session_params&& params, io_context& ios);
     session (session_params&& params, io_context& ios, session_flags_t);
     session (session_params const& params, io_context& ios);
    -session (session_params&& params, io_context& ios);
    +session (session_params const& params, io_context& ios, session_flags_t);
     

    Overload of the constructor that takes an external io_context to run the session object on. This is primarily useful for tests that may want @@ -10997,7 +11097,7 @@

    session()

    destruct the session_proxy object.

    [report issue]
    -
    +

    ~session()

     ~session ();
    @@ -11009,7 +11109,7 @@ 

    ~session()

    destructing the session object. Because it can take a few second for it to finish. The timeout can be set with apply_settings().

    [report issue]
    -
    +

    abort()

     session_proxy abort ();
    @@ -11038,13 +11138,13 @@ 

    session_params

     struct session_params
     {
    -   session_params (settings_pack&& sp);
        session_params (settings_pack const& sp);
    +   session_params (settings_pack&& sp);
        session_params ();
    -   session_params (settings_pack const& sp
    -      , std::vector<std::shared_ptr<plugin>> exts);
        session_params (settings_pack&& sp
           , std::vector<std::shared_ptr<plugin>> exts);
    +   session_params (settings_pack const& sp
    +      , std::vector<std::shared_ptr<plugin>> exts);
     
        settings_pack settings;
        std::vector<std::shared_ptr<plugin>> extensions;
    @@ -11055,24 +11155,24 @@ 

    session_params

    libtorrent::ip_filter ip_filter; };
    -[report issue]
    +[report issue]

    session_params()

    -session_params (settings_pack&& sp);
     session_params (settings_pack const& sp);
    +session_params (settings_pack&& sp);
     session_params ();
     

    This constructor can be used to start with the default plugins (ut_metadata, ut_pex and smart_ban). Pass a settings_pack to set the initial settings when the session starts.

    [report issue]
    -
    +

    session_params()

    -session_params (settings_pack const& sp
    -      , std::vector<std::shared_ptr<plugin>> exts);
     session_params (settings_pack&& sp
           , std::vector<std::shared_ptr<plugin>> exts);
    +session_params (settings_pack const& sp
    +      , std::vector<std::shared_ptr<plugin>> exts);
     

    This constructor helps to configure the set of initial plugins to be added to the session before it's started.

    @@ -11108,22 +11208,22 @@

    session_params()

    the IP filter to use for the session. This restricts which peers are allowed to connect. As if passed to set_ip_filter().
    - + -[report issue]
    +[report issue]
    -
    -

    write_session_params_buf() write_session_params() read_session_params()

    +
    +

    read_session_params() write_session_params() write_session_params_buf()

    Declared in "libtorrent/session_params.hpp"

     session_params read_session_params (bdecode_node const& e
        , save_state_flags_t flags = save_state_flags_t::all());
    +entry write_session_params (session_params const& sp
    +   , save_state_flags_t flags = save_state_flags_t::all());
     std::vector<char> write_session_params_buf (session_params const& sp
        , save_state_flags_t flags = save_state_flags_t::all());
     session_params read_session_params (span<char const> buf
        , save_state_flags_t flags = save_state_flags_t::all());
    -entry write_session_params (session_params const& sp
    -   , save_state_flags_t flags = save_state_flags_t::all());
     

    These functions serialize and de-serialize a session_params object to and from bencoded form. The session_params object is used to initialize a new @@ -11156,12 +11256,12 @@

    hasher

    class hasher { hasher (); + explicit hasher (span<char const> data); + hasher& operator= (hasher const&) &; hasher (hasher const&); hasher (char const* data, int len); - hasher& operator= (hasher const&) &; - explicit hasher (span<char const> data); - hasher& update (char const* data, int len); hasher& update (span<char const> data); + hasher& update (char const* data, int len); sha1_hash final (); void reset (); }; @@ -11170,10 +11270,10 @@

    hasher

    [report issue]

    hasher() operator=()

    +explicit hasher (span<char const> data);
    +hasher& operator= (hasher const&) &;
     hasher (hasher const&);
     hasher (char const* data, int len);
    -hasher& operator= (hasher const&) &;
    -explicit hasher (span<char const> data);
     

    this is the same as default constructing followed by a call to update(data, len).

    @@ -11181,8 +11281,8 @@

    hasher() operator=()

    update()

    -hasher& update (char const* data, int len);
     hasher& update (span<char const> data);
    +hasher& update (char const* data, int len);
     

    append the following bytes to what is being hashed

    [report issue]
    @@ -11194,7 +11294,7 @@

    final()

    returns the SHA-1 digest of the buffers previously passed to update() and the hasher constructor.

    [report issue]
    -
    +

    reset()

     void reset ();
    @@ -11211,11 +11311,11 @@ 

    hasher256

    { hasher256 (); hasher256 (hasher256 const&); + hasher256 (char const* data, int len); hasher256& operator= (hasher256 const&) &; explicit hasher256 (span<char const> data); - hasher256 (char const* data, int len); - hasher256& update (char const* data, int len); hasher256& update (span<char const> data); + hasher256& update (char const* data, int len); sha256_hash final (); void reset (); ~hasher256 (); @@ -11226,22 +11326,22 @@

    hasher256

    operator=() hasher256()

     hasher256 (hasher256 const&);
    +hasher256 (char const* data, int len);
     hasher256& operator= (hasher256 const&) &;
     explicit hasher256 (span<char const> data);
    -hasher256 (char const* data, int len);
     

    this is the same as default constructing followed by a call to update(data, len).

    [report issue]
    -
    +

    update()

    -hasher256& update (char const* data, int len);
     hasher256& update (span<char const> data);
    +hasher256& update (char const* data, int len);
     

    append the following bytes to what is being hashed

    [report issue]
    -
    +

    final()

     sha256_hash final ();
    @@ -11249,7 +11349,7 @@ 

    final()

    returns the SHA-1 digest of the buffers previously passed to update() and the hasher constructor.

    [report issue]
    -
    +

    reset()

     void reset ();
    @@ -11266,39 +11366,41 @@ 

    bitfield

     struct bitfield
     {
    -   bitfield (int bits, bool val);
        bitfield (bitfield&& rhs) noexcept = default;
    -   bitfield (char const* b, int bits);
    +   bitfield (bitfield const& rhs);
        explicit bitfield (int bits);
    +   bitfield (char const* b, int bits);
    +   bitfield (int bits, bool val);
        bitfield () noexcept = default;
    -   bitfield (bitfield const& rhs);
        void assign (char const* b, int const bits);
    -   bool get_bit (int index) const noexcept;
        bool operator[] (int index) const noexcept;
    -   void clear_bit (int index) noexcept;
    +   bool get_bit (int index) const noexcept;
        void set_bit (int index) noexcept;
    +   void clear_bit (int index) noexcept;
        bool all_set () const noexcept;
        bool none_set () const noexcept;
        int size () const noexcept;
        int num_words () const noexcept;
    +   int num_bytes () const noexcept;
        bool empty () const noexcept;
    -   char* data () noexcept;
        char const* data () const noexcept;
    +   char* data () noexcept;
        void swap (bitfield& rhs) noexcept;
        int count () const noexcept;
        int find_first_set () const noexcept;
        int find_last_clear () const noexcept;
    +   bool operator== (lt::bitfield const& rhs) const;
     };
     
    -[report issue]
    +[report issue]

    bitfield()

    -bitfield (int bits, bool val);
     bitfield (bitfield&& rhs) noexcept = default;
    -bitfield (char const* b, int bits);
    +bitfield (bitfield const& rhs);
     explicit bitfield (int bits);
    +bitfield (char const* b, int bits);
    +bitfield (int bits, bool val);
     bitfield () noexcept = default;
    -bitfield (bitfield const& rhs);
     

    constructs a new bitfield. The default constructor creates an empty bitfield. bits is the size of the bitfield (specified in bits). @@ -11320,17 +11422,17 @@

    assign()

    get_bit() operator[]()

    -bool get_bit (int index) const noexcept;
     bool operator[] (int index) const noexcept;
    +bool get_bit (int index) const noexcept;
     

    query bit at index. Returns true if bit is 1, otherwise false.

    - -[report issue]
    -
    -

    clear_bit() set_bit()

    + +[report issue]
    +
    +

    set_bit() clear_bit()

    -void clear_bit (int index) noexcept;
     void set_bit (int index) noexcept;
    +void clear_bit (int index) noexcept;
     

    set bit at index to 0 (clear_bit) or 1 (set_bit).

    [report issue]
    @@ -11362,6 +11464,14 @@

    num_words()

    returns the number of 32 bit words are needed to represent all bits in this bitfield.

    +[report issue]
    +
    +

    num_bytes()

    +
    +int num_bytes () const noexcept;
    +
    +

    returns the number of bytes needed to represent all bits in this +bitfield

    [report issue]

    empty()

    @@ -11370,16 +11480,16 @@

    empty()

    returns true if the bitfield has zero size.

    [report issue]
    -
    +

    data()

    -char* data () noexcept;
     char const* data () const noexcept;
    +char* data () noexcept;
     

    returns a pointer to the internal buffer of the bitfield, or nullptr if it's empty.

    [report issue]
    -
    +

    swap()

     void swap (bitfield& rhs) noexcept;
    @@ -11475,7 +11585,7 @@ 

    timestamp()

    a timestamp is automatically created in the constructor

    [report issue]
    -
    +

    type()

     virtual int type () const noexcept = 0;
    @@ -11491,7 +11601,7 @@ 

    type()

    for (alert* a : alerts) { switch (a->type()) { - case read_piece_alert::alert_type: + case read_piece_alert::alert_type: { auto* p = static_cast<read_piece_alert*>(a); if (p->ec) { @@ -11501,7 +11611,7 @@

    type()

    // use p break; } - case file_renamed_alert::alert_type: + case file_renamed_alert::alert_type: { // etc... } @@ -11575,7 +11685,7 @@

    torrent_alert

    torrent_handle handle; };
    -[report issue]
    +[report issue]

    message()

     std::string message () const override;
    @@ -11725,8 +11835,8 @@ 

    file_renamed_alert

    struct file_renamed_alert final : torrent_alert { std::string message () const override; - char const* old_name () const; char const* new_name () const; + char const* old_name () const; static constexpr alert_category_t static_category = alert_category::storage; file_index_t const index; @@ -11736,8 +11846,8 @@

    file_renamed_alert

    [report issue]

    new_name() old_name()

    -char const* old_name () const;
     char const* new_name () const;
    +char const* old_name () const;
     

    returns the new and previous file name, respectively.

    [report issue]
    @@ -12468,18 +12578,18 @@

    storage_moved_alert

    struct storage_moved_alert final : torrent_alert { std::string message () const override; - char const* old_path () const; char const* storage_path () const; + char const* old_path () const; static constexpr alert_category_t static_category = alert_category::storage; };
    - -[report issue]
    -

    old_path() storage_path()

    + +[report issue]
    +

    storage_path() old_path()

    -char const* old_path () const;
     char const* storage_path () const;
    +char const* old_path () const;
     

    the path the torrent was moved to and from, respectively.

    [report issue]
    @@ -12672,7 +12782,7 @@

    server_url()

    the URL the error is associated with

    [report issue]
    -
    +

    error_message()

     char const* error_message () const;
    @@ -13039,7 +13149,7 @@ 

    fastresume_rejected_alert

    operation_t op; };
    -[report issue]
    +[report issue]

    file_path()

     char const* file_path () const;
    @@ -13256,7 +13366,7 @@ 

    torrent_error_alert

    error_code const error; };
    -[report issue]
    +[report issue]

    filename()

     char const* filename () const;
    @@ -13616,7 +13726,7 @@ 

    log_alert

    static constexpr alert_category_t static_category = alert_category::session_log; };
    -[report issue]
    +[report issue]

    log_message()

     char const* log_message () const;
    @@ -13640,7 +13750,7 @@ 

    torrent_log_alert

    static constexpr alert_category_t static_category = alert_category::torrent_log; };
    -[report issue]
    +[report issue]

    log_message()

     char const* log_message () const;
    @@ -13675,14 +13785,14 @@ 

    peer_log_alert

    direction_t direction; };
    -[report issue]
    +[report issue]

    log_message()

     char const* log_message () const;
     

    returns the log message

    [report issue]
    -
    +

    enum direction_t

    Declared in "libtorrent/alert_types.hpp"

    @@ -13903,7 +14013,7 @@

    dht_log_alert

    dht_module_t module; }; -[report issue]
    +[report issue]

    log_message()

     char const* log_message () const;
    @@ -13987,7 +14097,7 @@ 

    pkt_buf()

    is valid, which is owned by libtorrent and reclaimed whenever pop_alerts() is called on the session.

    [report issue]
    -
    +

    enum direction_t

    Declared in "libtorrent/alert_types.hpp"

    @@ -14125,19 +14235,19 @@

    dht_live_nodes_alert

    struct dht_live_nodes_alert final : alert { std::string message () const override; - std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; int num_nodes () const; + std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; static constexpr alert_category_t static_category = alert_category::dht; sha1_hash node_id; }; - -[report issue]
    -

    nodes() num_nodes()

    + +[report issue]
    +

    num_nodes() nodes()

    -std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const;
     int num_nodes () const;
    +std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const;
     

    the number of nodes in the routing table and the actual nodes.

    [report issue]
    @@ -14174,8 +14284,8 @@

    dht_sample_infohashes_alert

    struct dht_sample_infohashes_alert final : alert { std::string message () const override; - int num_samples () const; std::vector<sha1_hash> samples () const; + int num_samples () const; int num_nodes () const; std::vector<std::pair<sha1_hash, udp::endpoint>> nodes () const; @@ -14190,8 +14300,8 @@

    dht_sample_infohashes_alert

    [report issue]

    num_samples() samples()

    -int num_samples () const;
     std::vector<sha1_hash> samples () const;
    +int num_samples () const;
     

    returns the number of info-hashes returned by the node, as well as the actual info-hashes. num_samples() is more efficient than @@ -14380,6 +14490,101 @@

    torrent_conflict_alert

    One way to resolve the conflict is to remove both failing torrents and re-add it using this metadata
    +[report issue]
    +
    +

    peer_info_alert

    +

    Declared in "libtorrent/alert_types.hpp"

    +

    posted when torrent_handle::post_peer_info() is called

    +
    +struct peer_info_alert final : torrent_alert
    +{
    +   std::string message () const override;
    +
    +   static constexpr alert_category_t static_category  = alert_category::status;
    +   std::vector<lt::peer_info> peer_info;
    +};
    +
    +[report issue]
    +
    peer_info
    +
    the list of the currently connected peers
    +
    +[report issue]
    +
    +

    file_progress_alert

    +

    Declared in "libtorrent/alert_types.hpp"

    +

    posted when torrent_handle::post_file_progress() is called

    +
    +struct file_progress_alert final : torrent_alert
    +{
    +   std::string message () const override;
    +
    +   static constexpr alert_category_t static_category  = alert_category::file_progress;
    +   aux::vector<std::int64_t, file_index_t> files;
    +};
    +
    +[report issue]
    +
    files
    +
    the list of the files in the torrent
    +
    +[report issue]
    +
    +

    piece_info_alert

    +

    Declared in "libtorrent/alert_types.hpp"

    +

    posted when torrent_handle::post_download_queue() is called

    +
    +struct piece_info_alert final : torrent_alert
    +{
    +   std::string message () const override;
    +
    +   static constexpr alert_category_t static_category  = alert_category::piece_progress;
    +   std::vector<partial_piece_info> piece_info;
    +   std::vector<block_info> block_data;
    +};
    +
    +[report issue]
    +
    piece_info
    +
    info about pieces being downloaded for the torrent
    +
    +[report issue]
    +
    block_data
    +
    storage for block_info pointers in partial_piece_info objects
    +
    +[report issue]
    +
    +

    piece_availability_alert

    +

    Declared in "libtorrent/alert_types.hpp"

    +

    posted when torrent_handle::post_piece_availability() is called

    +
    +struct piece_availability_alert final : torrent_alert
    +{
    +   std::string message () const override;
    +
    +   static constexpr alert_category_t static_category  = alert_category::status;
    +   std::vector<int> piece_availability;
    +};
    +
    +[report issue]
    +
    piece_availability
    +
    info about pieces being downloaded for the torrent
    +
    +[report issue]
    +
    +

    tracker_list_alert

    +

    Declared in "libtorrent/alert_types.hpp"

    +

    posted when torrent_handle::post_trackers() is called

    +
    +struct tracker_list_alert final : torrent_alert
    +{
    +   std::string message () const override;
    +
    +   static constexpr alert_category_t static_category  = alert_category::status;
    +   std::vector<announce_entry> trackers;
    +};
    +
    +[report issue]
    +
    trackers
    +
    list of trackers and their status for the torrent
    +
    [report issue]

    alert_cast()

    @@ -14617,7 +14822,7 @@

    enum operation_t

    [report issue]
    -
    +

    int

    Declared in "libtorrent/alert_types.hpp"

    @@ -14775,38 +14980,38 @@

    bdecode_node

    struct bdecode_node { bdecode_node () = default; - bdecode_node (bdecode_node const&); - bdecode_node& operator= (bdecode_node const&) &; bdecode_node (bdecode_node&&) noexcept; + bdecode_node& operator= (bdecode_node const&) &; bdecode_node& operator= (bdecode_node&&) & = default; + bdecode_node (bdecode_node const&); type_t type () const noexcept; explicit operator bool () const noexcept; bdecode_node non_owning () const; - std::ptrdiff_t data_offset () const noexcept; span<char const> data_section () const noexcept; - int list_size () const; - string_view list_string_value_at (int i - , string_view default_val = string_view()) const; + std::ptrdiff_t data_offset () const noexcept; std::int64_t list_int_value_at (int i , std::int64_t default_val = 0) const; + string_view list_string_value_at (int i + , string_view default_val = string_view()) const; bdecode_node list_at (int i) const; + int list_size () const; bdecode_node dict_find_dict (string_view key) const; + std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const; + bdecode_node dict_find_list (string_view key) const; + int dict_size () const; bdecode_node dict_find (string_view key) const; - string_view dict_find_string_value (string_view key - , string_view default_value = string_view()) const; bdecode_node dict_find_string (string_view key) const; bdecode_node dict_find_int (string_view key) const; + string_view dict_find_string_value (string_view key + , string_view default_value = string_view()) const; std::int64_t dict_find_int_value (string_view key , std::int64_t default_val = 0) const; - int dict_size () const; - std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const; std::pair<string_view, bdecode_node> dict_at (int i) const; - bdecode_node dict_find_list (string_view key) const; std::int64_t int_value () const; int string_length () const; - string_view string_value () const; - char const* string_ptr () const; std::ptrdiff_t string_offset () const; + char const* string_ptr () const; + string_view string_value () const; void clear (); void swap (bdecode_node& n); void reserve (int tokens); @@ -14823,33 +15028,33 @@

    bdecode_node

    }; }; -[report issue]
    +[report issue]

    bdecode_node()

     bdecode_node () = default;
     

    creates a default constructed node, it will have the type none_t.

    - -[report issue]
    -
    -

    bdecode_node() operator=()

    + +[report issue]
    +
    +

    operator=() bdecode_node()

    -bdecode_node (bdecode_node const&);
    -bdecode_node& operator= (bdecode_node const&) &;
     bdecode_node (bdecode_node&&) noexcept;
    +bdecode_node& operator= (bdecode_node const&) &;
     bdecode_node& operator= (bdecode_node&&) & = default;
    +bdecode_node (bdecode_node const&);
     

    For owning nodes, the copy will create a copy of the tree, but the underlying buffer remains the same.

    [report issue]
    -
    +

    type()

     type_t type () const noexcept;
     

    the type of this node. See type_t.

    [report issue]
    -
    +

    bool()

     explicit operator bool () const noexcept;
    @@ -14863,13 +15068,13 @@ 

    non_owning()

    return a non-owning reference to this node. This is useful to refer to the root node without copying it in assignments.

    - -[report issue]
    -
    -

    data_offset() data_section()

    + +[report issue]
    +
    +

    data_section() data_offset()

    -std::ptrdiff_t data_offset () const noexcept;
     span<char const> data_section () const noexcept;
    +std::ptrdiff_t data_offset () const noexcept;
     

    returns the buffer and length of the section in the original bencoded buffer where this node is defined. For a dictionary for instance, this @@ -14878,48 +15083,48 @@

    data_offset() data_section()

    the data_offset() function returns the byte-offset to this node in, starting from the beginning of the buffer that was parsed.

    + - -[report issue]
    -
    -

    list_int_value_at() list_size() list_string_value_at() list_at()

    +[report issue]
    +
    +

    list_int_value_at() list_at() list_size() list_string_value_at()

    -int list_size () const;
    -string_view list_string_value_at (int i
    -      , string_view default_val = string_view()) const;
     std::int64_t list_int_value_at (int i
           , std::int64_t default_val = 0) const;
    +string_view list_string_value_at (int i
    +      , string_view default_val = string_view()) const;
     bdecode_node list_at (int i) const;
    +int list_size () const;
     

    functions with the list_ prefix operate on lists. These functions are only valid if type() == list_t. list_at() returns the item in the list at index i. i may not be greater than or equal to the size of the list. size() returns the size of the list.

    - - - - - - + + + + + -[report issue]
    -
    -

    dict_find_string() dict_find_dict() dict_find_int() dict_find_string_value() dict_at_node() dict_find() dict_find_list() dict_find_int_value() dict_size() dict_at()

    + +[report issue]
    +
    +

    dict_find() dict_find_string_value() dict_at() dict_find_int() dict_find_dict() dict_find_int_value() dict_find_string() dict_size() dict_find_list() dict_at_node()

     bdecode_node dict_find_dict (string_view key) const;
    +std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const;
    +bdecode_node dict_find_list (string_view key) const;
    +int dict_size () const;
     bdecode_node dict_find (string_view key) const;
    -string_view dict_find_string_value (string_view key
    -      , string_view default_value = string_view()) const;
     bdecode_node dict_find_string (string_view key) const;
     bdecode_node dict_find_int (string_view key) const;
    +string_view dict_find_string_value (string_view key
    +      , string_view default_value = string_view()) const;
     std::int64_t dict_find_int_value (string_view key
           , std::int64_t default_val = 0) const;
    -int dict_size () const;
    -std::pair<bdecode_node, bdecode_node> dict_at_node (int i) const;
     std::pair<string_view, bdecode_node> dict_at (int i) const;
    -bdecode_node dict_find_list (string_view key) const;
     

    Functions with the dict_ prefix operates on dictionaries. They are only valid if type() == dict_t. In case a key you're looking up @@ -14942,17 +15147,17 @@

    int_value()

    this function is only valid if type() == int_t. It returns the value of the integer.

    - - + -[report issue]
    -
    -

    string_ptr() string_value() string_offset() string_length()

    + +[report issue]
    +
    +

    string_length() string_offset() string_ptr() string_value()

     int string_length () const;
    -string_view string_value () const;
    -char const* string_ptr () const;
     std::ptrdiff_t string_offset () const;
    +char const* string_ptr () const;
    +string_view string_value () const;
     

    these functions are only valid if type() == string_t. They return the string values. Note that string_ptr() is not 0-terminated. @@ -14960,7 +15165,7 @@

    string_ptr() string_value() string_offset() string_length()

    string_offset() returns the byte offset from the start of the parsed bencoded buffer this string can be found.

    [report issue]
    -
    +

    clear()

     void clear ();
    @@ -14968,14 +15173,14 @@ 

    clear()

    resets the bdecoded_node to a default constructed state. If this is an owning node, the tree is freed and all child nodes are invalidated.

    [report issue]
    -
    +

    swap()

     void swap (bdecode_node& n);
     

    Swap contents.

    [report issue]
    -
    +

    reserve()

     void reserve (int tokens);
    @@ -15120,7 +15325,7 @@ 

    bdecode()

    // reads the files and calculates the hashes set_piece_hashes(t, "."); -ofstream out("my_torrent.torrent", std::ios_base::binary); +ofstream out("my_torrent.torrent", std::ios_base::binary); std::vector<char> buf = t.generate_buf(); out.write(buf.data(), buf.size()); @@ -15139,9 +15344,9 @@

    create_torrent

     struct create_torrent
     {
    +   explicit create_torrent (torrent_info const& ti);
        explicit create_torrent (file_storage& fs, int piece_size = 0
           , create_flags_t flags = {});
    -   explicit create_torrent (torrent_info const& ti);
        std::vector<char> generate_buf () const;
        entry generate () const;
        file_storage const& files () const;
    @@ -15157,8 +15362,8 @@ 

    create_torrent

    void set_root_cert (string_view cert); void set_priv (bool p); bool priv () const; - bool is_v2_only () const; bool is_v1_only () const; + bool is_v2_only () const; int num_pieces () const; piece_index_t end_piece () const; index_range<piece_index_t> piece_range () const noexcept; @@ -15168,8 +15373,8 @@

    create_torrent

    std::int64_t total_size () const; int piece_length () const; int piece_size (piece_index_t i) const; - void add_collection (string_view c); void add_similar_torrent (sha1_hash ih); + void add_collection (string_view c); static constexpr create_flags_t modification_time = 2_bit; static constexpr create_flags_t symlinks = 3_bit; @@ -15180,12 +15385,12 @@

    create_torrent

    static constexpr create_flags_t canonical_files_no_tail_padding = 9_bit; };
    -[report issue]
    +[report issue]

    create_torrent()

    +explicit create_torrent (torrent_info const& ti);
     explicit create_torrent (file_storage& fs, int piece_size = 0
           , create_flags_t flags = {});
    -explicit create_torrent (torrent_info const& ti);
     

    The piece_size is the size of each piece in bytes. It must be a power of 2 and a minimum of 16 kiB. If a piece size of 0 is @@ -15304,10 +15509,10 @@

    set_hash2()

    when calling generate(). This function will throw std::system_error if it is called on an object constructed with the v1_only flag.

    - -[report issue]
    -
    -

    add_url_seed() add_http_seed()

    + +[report issue]
    +
    +

    add_http_seed() add_url_seed()

     void add_http_seed (string_view url);
     void add_url_seed (string_view url);
    @@ -15372,14 +15577,14 @@ 

    num_pieces()

    returns the number of pieces in the associated file_storage object.

    [report issue]
    -
    +

    piece_range()

     index_range<piece_index_t> piece_range () const noexcept;
     

    all piece indices in the torrent to be created

    [report issue]
    -
    +

    file_range()

     index_range<file_index_t> file_range () const noexcept;
    @@ -15395,7 +15600,7 @@ 

    file_piece_range()

    specified file, specified as delta from the first piece in the file. i.e. the first index is 0.

    [report issue]
    -
    +

    total_size()

     std::int64_t total_size () const;
    @@ -15417,8 +15622,8 @@ 

    piece_length() piece_size()

    add_similar_torrent() add_collection()

    -void add_collection (string_view c);
     void add_similar_torrent (sha1_hash ih);
    +void add_collection (string_view c);
     

    Add similar torrents (by info-hash) or collections of similar torrents. Similar torrents are expected to share some files with this torrent. @@ -15490,10 +15695,10 @@

    add_similar_torrent() add_collection()

    add_files()

    Declared in "libtorrent/create_torrent.hpp"

    -void add_files (file_storage& fs, std::string const& file
    -   , create_flags_t flags = {});
     void add_files (file_storage& fs, std::string const& file
        , std::function<bool(std::string)> p, create_flags_t flags = {});
    +void add_files (file_storage& fs, std::string const& file
    +   , create_flags_t flags = {});
     

    Adds the file specified by path to the file_storage object. In case path refers to a directory, files will be added recursively from the directory.

    @@ -15514,21 +15719,21 @@

    add_files()

    set_piece_hashes()

    Declared in "libtorrent/create_torrent.hpp"

    +inline void set_piece_hashes (create_torrent& t, std::string const& p, error_code& ec);
    +inline void set_piece_hashes (create_torrent& t, std::string const& p
    +   , std::function<void(piece_index_t)> const& f);
     inline void set_piece_hashes (create_torrent& t, std::string const& p
        , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f);
     void set_piece_hashes (create_torrent& t, std::string const& p
    -   , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f, error_code& ec);
    -inline void set_piece_hashes (create_torrent& t, std::string const& p, error_code& ec);
     void set_piece_hashes (create_torrent& t, std::string const& p
    +   , settings_interface const& settings, disk_io_constructor_type disk_io
        , std::function<void(piece_index_t)> const& f, error_code& ec);
     void set_piece_hashes (create_torrent& t, std::string const& p
    -   , settings_interface const& settings, disk_io_constructor_type disk_io
    +   , settings_interface const& settings
        , std::function<void(piece_index_t)> const& f, error_code& ec);
     inline void set_piece_hashes (create_torrent& t, std::string const& p);
    -inline void set_piece_hashes (create_torrent& t, std::string const& p
    -   , std::function<void(piece_index_t)> const& f);
     

    This function will assume that the files added to the torrent file exists at path p, read those files and hash the content and set the hashes in the create_torrent @@ -15567,7 +15772,7 @@

    stats_metric

    session_stats_alert object.
    [report issue]
    -
    +

    counters

    Declared in "libtorrent/performance_counters.hpp"

    @@ -15578,8 +15783,8 @@ 

    counters

    counters (counters const&) ; std::int64_t operator[] (int i) const ; std::int64_t inc_stats_counter (int c, std::int64_t value = 1) ; - void set_value (int c, std::int64_t value) ; void blend_stats_counter (int c, std::int64_t value, int ratio) ; + void set_value (int c, std::int64_t value) ; };
    @@ -15738,7 +15943,7 @@

    torrent_status

    torrent_flags_t flags {}; }; -[report issue]
    +[report issue]

    operator==()

     bool operator== (torrent_status const& st) const;
    @@ -16228,14 +16433,14 @@ 

    storage_error

    struct storage_error { explicit operator bool () const; - void file (file_index_t f); file_index_t file () const; + void file (file_index_t f); error_code ec; operation_t operation; };
    -[report issue]
    +[report issue]

    bool()

     explicit operator bool () const;
    @@ -16246,8 +16451,8 @@ 

    bool()

    file()

    -void file (file_index_t f);
     file_index_t file () const;
    +void file (file_index_t f);
     

    set and query the index (in the torrent) of the file this error occurred on. This may also have special values defined in @@ -16473,7 +16678,7 @@

    enum i2p_error_code

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/bdecode.hpp"

    @@ -16528,7 +16733,7 @@

    enum error_code_enum

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/upnp.hpp"

    @@ -16597,7 +16802,7 @@

    enum error_code_enum

    [report issue]
    -
    +

    enum error_code_enum

    Declared in "libtorrent/error_code.hpp"

    @@ -17587,38 +17792,38 @@

    entry

    class entry { data_type type () const; - entry (integer_type); - entry (span<char const>); - entry (list_type); entry (preformatted_type); entry (dictionary_type); + entry (integer_type); + entry (list_type); + entry (span<char const>); entry (U v); entry (data_type t); entry (bdecode_node const& n); - entry& operator= (bdecode_node const&) &; - entry& operator= (dictionary_type) &; - entry& operator= (integer_type) &; entry& operator= (preformatted_type) &; - entry& operator= (list_type) &; + entry& operator= (bdecode_node const&) &; entry& operator= (entry const&) &; - entry& operator= (entry&&) & noexcept; + entry& operator= (integer_type) &; + entry& operator= (dictionary_type) &; entry& operator= (span<char const>) &; + entry& operator= (entry&&) & noexcept; + entry& operator= (list_type) &; entry& operator= (U v) &; - preformatted_type const& preformatted () const; list_type const& list () const; - string_type const& string () const; + dictionary_type const& dict () const; integer_type const& integer () const; + dictionary_type& dict (); + preformatted_type const& preformatted () const; + list_type& list (); string_type& string (); + string_type const& string () const; integer_type& integer (); - list_type& list (); - dictionary_type& dict (); - dictionary_type const& dict () const; preformatted_type& preformatted (); void swap (entry& e); entry& operator[] (string_view key); entry const& operator[] (string_view key) const; - entry const* find_key (string_view key) const; entry* find_key (string_view key); + entry const* find_key (string_view key) const; std::string to_string (bool single_line = false) const; enum data_type @@ -17632,27 +17837,27 @@

    entry

    }; }; -[report issue]
    +[report issue]

    type()

     data_type type () const;
     

    returns the concrete type of the entry

    [report issue]
    -
    +

    entry()

    -entry (integer_type);
    -entry (span<char const>);
    -entry (list_type);
     entry (preformatted_type);
     entry (dictionary_type);
    +entry (integer_type);
    +entry (list_type);
    +entry (span<char const>);
     

    constructors directly from a specific type. The content of the argument is copied into the newly constructed entry

    [report issue]
    -
    +

    entry()

     entry (data_type t);
    @@ -17660,44 +17865,44 @@ 

    entry()

    construct an empty entry of the specified type. see data_type enum.

    [report issue]
    -
    +

    entry()

     entry (bdecode_node const& n);
     

    construct from bdecode_node parsed form (see bdecode())

    [report issue]
    -
    +

    operator=()

    -entry& operator= (bdecode_node const&) &;
    -entry& operator= (dictionary_type) &;
    -entry& operator= (integer_type) &;
     entry& operator= (preformatted_type) &;
    -entry& operator= (list_type) &;
    +entry& operator= (bdecode_node const&) &;
     entry& operator= (entry const&) &;
    -entry& operator= (entry&&) & noexcept;
    +entry& operator= (integer_type) &;
    +entry& operator= (dictionary_type) &;
     entry& operator= (span<char const>) &;
    +entry& operator= (entry&&) & noexcept;
    +entry& operator= (list_type) &;
     

    copies the structure of the right hand side into this entry.

    - - -[report issue]
    -
    -

    preformatted() dict() integer() list() string()

    + + +[report issue]
    +
    +

    dict() list() string() integer() preformatted()

    -preformatted_type const& preformatted () const;
     list_type const& list () const;
    -string_type const& string () const;
    +dictionary_type const& dict () const;
     integer_type const& integer () const;
    +dictionary_type& dict ();
    +preformatted_type const& preformatted () const;
    +list_type& list ();
     string_type& string ();
    +string_type const& string () const;
     integer_type& integer ();
    -list_type& list ();
    -dictionary_type& dict ();
    -dictionary_type const& dict () const;
     preformatted_type& preformatted ();
     

    The integer(), string(), list() and dict() functions @@ -17740,14 +17945,14 @@

    preformatted() dict() integer() list() string()

    To make it easier to extract information from a torrent file, the class torrent_info exists.

    [report issue]
    -
    +

    swap()

     void swap (entry& e);
     

    swaps the content of this with e.

    [report issue]
    -
    +

    operator[]()

     entry& operator[] (string_view key);
    @@ -17766,8 +17971,8 @@ 

    operator[]()

    find_key()

    -entry const* find_key (string_view key) const;
     entry* find_key (string_view key);
    +entry const* find_key (string_view key) const;
     

    These functions requires the entry to be a dictionary, if it isn't they will throw system_error.

    @@ -17827,7 +18032,7 @@

    enum data_type

    [report issue]
    -
    +

    operator<<()

    Declared in "libtorrent/entry.hpp"

    @@ -17851,7 +18056,7 @@ 

    bencode()

    function assumes the value_type of the iterator is a char. In order to encode entry e into a buffer, do:

    -std::vector<char> buffer;
    +std::vector<char> buf;
     bencode(std::back_inserter(buf), e);
     
    [report issue]
    @@ -17867,12 +18072,12 @@

    ip_filter

     struct ip_filter
     {
    -   ip_filter (ip_filter const&);
    +   ip_filter ();
        ip_filter& operator= (ip_filter const&);
        ~ip_filter ();
    -   ip_filter& operator= (ip_filter&&);
    -   ip_filter ();
        ip_filter (ip_filter&&);
    +   ip_filter& operator= (ip_filter&&);
    +   ip_filter (ip_filter const&);
        bool empty () const;
        void add_rule (address const& first, address const& last, std::uint32_t flags);
        std::uint32_t access (address const& addr) const;
    @@ -17884,7 +18089,7 @@ 

    ip_filter

    }; };
    -[report issue]
    +[report issue]

    empty()

     bool empty () const;
    @@ -17964,11 +18169,11 @@ 

    port_filter

     class port_filter
     {
    -   port_filter& operator= (port_filter&&);
    -   port_filter (port_filter const&);
        ~port_filter ();
    -   port_filter& operator= (port_filter const&);
    +   port_filter (port_filter const&);
        port_filter ();
    +   port_filter& operator= (port_filter const&);
    +   port_filter& operator= (port_filter&&);
        port_filter (port_filter&&);
        void add_rule (std::uint16_t first, std::uint16_t last, std::uint32_t flags);
        std::uint32_t access (std::uint16_t port) const;
    @@ -17979,7 +18184,7 @@ 

    port_filter

    }; };
    -[report issue]
    +[report issue]

    add_rule()

     void add_rule (std::uint16_t first, std::uint16_t last, std::uint32_t flags);
    @@ -17988,7 +18193,7 @@ 

    add_rule()

    flags overwriting any existing rule for those ports. The range is inclusive, i.e. the port last also has the flag set on it.

    [report issue]
    -
    +

    access()

     std::uint32_t access (std::uint16_t port) const;
    @@ -17997,7 +18202,7 @@ 

    access()

    or not. The returned value is the flags set for this port. see access_flags.

    [report issue]
    -
    +

    enum access_flags

    Declared in "libtorrent/ip_filter.hpp"

    @@ -18030,8 +18235,8 @@

    block_info

     struct block_info
     {
    -   tcp::endpoint peer () const;
        void set_peer (tcp::endpoint const& ep);
    +   tcp::endpoint peer () const;
     
        enum block_state_t
        {
    @@ -18051,8 +18256,8 @@ 

    block_info

    [report issue]

    set_peer() peer()

    -tcp::endpoint peer () const;
     void set_peer (tcp::endpoint const& ep);
    +tcp::endpoint peer () const;
     

    The peer is the ip address of the peer this block was downloaded from.

    [report issue]
    @@ -18158,7 +18363,9 @@

    partial_piece_info

    Warning

    This is a pointer that points to an array that's owned by the session object. The next time -get_download_queue() is called, it will be invalidated.

    +get_download_queue() is called, it will be invalidated. +In the case of piece_info_alert, these pointers point into the alert +object itself, and will be invalidated when the alert destruct.

    @@ -18197,26 +18404,31 @@

    torrent_handle

    { friend std::size_t hash_value (torrent_handle const& th); torrent_handle () noexcept = default; - void add_piece (piece_index_t piece, std::vector<char> data, add_piece_flags_t flags = {}) const; void add_piece (piece_index_t piece, char const* data, add_piece_flags_t flags = {}) const; + void add_piece (piece_index_t piece, std::vector<char> data, add_piece_flags_t flags = {}) const; void read_piece (piece_index_t piece) const; bool have_piece (piece_index_t piece) const; + void post_peer_info () const; void get_peer_info (std::vector<peer_info>& v) const; + void post_status (status_flags_t flags = status_flags_t::all()) const; torrent_status status (status_flags_t flags = status_flags_t::all()) const; std::vector<partial_piece_info> get_download_queue () const; + void post_download_queue () const; void get_download_queue (std::vector<partial_piece_info>& queue) const; - void reset_piece_deadline (piece_index_t index) const; - void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const; void clear_piece_deadlines () const; + void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const; + void reset_piece_deadline (piece_index_t index) const; + void post_file_progress (file_progress_flags_t flags) const; std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const; void file_progress (std::vector<std::int64_t>& progress, file_progress_flags_t flags = {}) const; std::vector<open_file_state> file_status () const; void clear_error () const; void add_tracker (announce_entry const&) const; - std::vector<announce_entry> trackers () const; void replace_trackers (std::vector<announce_entry> const&) const; - std::set<std::string> url_seeds () const; + void post_trackers () const; + std::vector<announce_entry> trackers () const; void add_url_seed (std::string const& url) const; + std::set<std::string> url_seeds () const; void remove_url_seed (std::string const& url) const; std::set<std::string> http_seeds () const; void add_http_seed (std::string const& url) const; @@ -18226,66 +18438,68 @@

    torrent_handle

    , client_data_t userdata = client_data_t{}); bool set_metadata (span<char const> metadata) const; bool is_valid () const; - void resume () const; void pause (pause_flags_t flags = {}) const; - void unset_flags (torrent_flags_t flags) const; - torrent_flags_t flags () const; + void resume () const; void set_flags (torrent_flags_t flags) const; + torrent_flags_t flags () const; void set_flags (torrent_flags_t flags, torrent_flags_t mask) const; + void unset_flags (torrent_flags_t flags) const; void flush_cache () const; void force_recheck () const; void save_resume_data (resume_data_flags_t flags = {}) const; + bool need_save_resume_data (resume_data_flags_t flags) const; bool need_save_resume_data () const; - void queue_position_top () const; queue_position_t queue_position () const; - void queue_position_bottom () const; - void queue_position_up () const; void queue_position_down () const; + void queue_position_top () const; + void queue_position_up () const; + void queue_position_bottom () const; void queue_position_set (queue_position_t p) const; + void set_ssl_certificate_buffer (std::string const& certificate + , std::string const& private_key + , std::string const& dh_params); void set_ssl_certificate (std::string const& certificate , std::string const& private_key , std::string const& dh_params , std::string const& passphrase = ""); - void set_ssl_certificate_buffer (std::string const& certificate - , std::string const& private_key - , std::string const& dh_params); std::shared_ptr<torrent_info> torrent_file_with_hashes () const; std::shared_ptr<const torrent_info> torrent_file () const; std::vector<std::vector<sha256_hash>> piece_layers () const; void piece_availability (std::vector<int>& avail) const; + void post_piece_availability () const; + download_priority_t piece_priority (piece_index_t index) const; std::vector<download_priority_t> get_piece_priorities () const; + void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const; void prioritize_pieces (std::vector<download_priority_t> const& pieces) const; void piece_priority (piece_index_t index, download_priority_t priority) const; - void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const; - download_priority_t piece_priority (piece_index_t index) const; + download_priority_t file_priority (file_index_t index) const; void prioritize_files (std::vector<download_priority_t> const& files) const; void file_priority (file_index_t index, download_priority_t priority) const; std::vector<download_priority_t> get_file_priorities () const; - download_priority_t file_priority (file_index_t index) const; - void force_lsd_announce () const; - void force_dht_announce () const; void force_reannounce (int seconds = 0, int idx = -1, reannounce_flags_t = {}) const; + void force_dht_announce () const; + void force_lsd_announce () const; void scrape_tracker (int idx = -1) const; int upload_limit () const; + void set_upload_limit (int limit) const; int download_limit () const; void set_download_limit (int limit) const; - void set_upload_limit (int limit) const; void connect_peer (tcp::endpoint const& adr, peer_source_flags_t source = {} , pex_flags_t flags = pex_encryption | pex_utp | pex_holepunch) const; void clear_peers (); - int max_uploads () const; void set_max_uploads (int max_uploads) const; - int max_connections () const; + int max_uploads () const; void set_max_connections (int max_connections) const; + int max_connections () const; void move_storage (std::string const& save_path , move_flags_t flags = move_flags_t::always_replace_files ) const; void rename_file (file_index_t index, std::string const& new_name) const; - sha1_hash info_hash () const; info_hash_t info_hashes () const; - bool operator< (const torrent_handle& h) const; - bool operator!= (const torrent_handle& h) const; + sha1_hash info_hash () const; bool operator== (const torrent_handle& h) const; + bool operator!= (const torrent_handle& h) const; + bool operator< (const torrent_handle& h) const; std::uint32_t id () const; std::shared_ptr<torrent> native_handle () const; client_data_t userdata () const; @@ -18306,10 +18520,15 @@

    torrent_handle

    static constexpr resume_data_flags_t flush_disk_cache = 0_bit; static constexpr resume_data_flags_t save_info_dict = 1_bit; static constexpr resume_data_flags_t only_if_modified = 2_bit; + static constexpr resume_data_flags_t if_counters_changed = 3_bit; + static constexpr resume_data_flags_t if_download_progress = 4_bit; + static constexpr resume_data_flags_t if_config_changed = 5_bit; + static constexpr resume_data_flags_t if_state_changed = 6_bit; + static constexpr resume_data_flags_t if_metadata_changed = 7_bit; static constexpr reannounce_flags_t ignore_min_interval = 0_bit; };
    -[report issue]
    +[report issue]

    torrent_handle()

     torrent_handle () noexcept = default;
    @@ -18320,8 +18539,8 @@ 

    torrent_handle()

    add_piece()

    -void add_piece (piece_index_t piece, std::vector<char> data, add_piece_flags_t flags = {}) const;
     void add_piece (piece_index_t piece, char const* data, add_piece_flags_t flags = {}) const;
    +void add_piece (piece_index_t piece, std::vector<char> data, add_piece_flags_t flags = {}) const;
     

    This function will write data to the storage as piece piece, as if it had been downloaded from a peer.

    @@ -18366,21 +18585,30 @@

    have_piece()

    Returns true if this piece has been completely downloaded and written to disk, and false otherwise.

    -[report issue]
    -
    -

    get_peer_info()

    + +[report issue]
    +
    +

    get_peer_info() post_peer_info()

    +void post_peer_info () const;
     void get_peer_info (std::vector<peer_info>& v) const;
     
    -

    takes a reference to a vector that will be cleared and filled with one -entry for each peer connected to this torrent, given the handle is -valid. If the torrent_handle is invalid, it will throw -system_error exception. Each entry in the vector contains -information about that particular peer. See peer_info.

    -[report issue]
    -
    -

    status()

    -
    +

    Query information about connected peers for this torrent. If the +torrent_handle is invalid, it will throw a system_error exception.

    +

    post_peer_info() is asynchronous and will trigger the posting of +a peer_info_alert. The alert contain a list of peer_info objects, one +for each connected peer.

    +

    get_peer_info() is synchronous and takes a reference to a vector +that will be cleared and filled with one entry for each peer +connected to this torrent, given the handle is valid. Each entry in +the vector contains information about that particular peer. See +peer_info.

    + +[report issue]
    +
    +

    post_status() status()

    +
    +void post_status (status_flags_t flags = status_flags_t::all()) const;
     torrent_status status (status_flags_t flags = status_flags_t::all()) const;
     

    status() will return a structure with information about the status @@ -18390,28 +18618,39 @@

    status()

    Some information in there is relatively expensive to calculate, and if you're not interested in it (and see performance issues), you can filter them out.

    +

    The status() function will block until the internal libtorrent +thread responds with the torrent_status object. To avoid blocking, +instead call post_status(). It will trigger posting of a +state_update_alert with a single torrent_status object for this +torrent.

    +

    In order to get regular updates for torrents whose status changes, +consider calling session::post_torrent_updates()`` instead.

    By default everything is included. The flags you can use to decide what to include are defined in this class.

    -[report issue]
    -
    -

    get_download_queue()

    + +[report issue]
    +
    +

    get_download_queue() post_download_queue()

     std::vector<partial_piece_info> get_download_queue () const;
    +void post_download_queue () const;
     void get_download_queue (std::vector<partial_piece_info>& queue) const;
     
    -

    get_download_queue() returns a vector with information about pieces -that are partially downloaded or not downloaded but partially -requested. See partial_piece_info for the fields in the returned -vector.

    +

    post_download_queue() triggers a download_queue_alert to be +posted. +get_download_queue() is a synchronous call and returns a vector +with information about pieces that are partially downloaded or not +downloaded but partially requested. See partial_piece_info for the +fields in the returned vector.

    - -[report issue]
    -
    -

    clear_piece_deadlines() reset_piece_deadline() set_piece_deadline()

    + +[report issue]
    +
    +

    clear_piece_deadlines() set_piece_deadline() reset_piece_deadline()

    -void reset_piece_deadline (piece_index_t index) const;
    -void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const;
     void clear_piece_deadlines () const;
    +void set_piece_deadline (piece_index_t index, int deadline, deadline_flags_t flags = {}) const;
    +void reset_piece_deadline (piece_index_t index) const;
     

    This function sets or resets the deadline associated with a specific piece index (index). libtorrent will attempt to download this @@ -18430,10 +18669,12 @@

    clear_piece_deadlines() reset_piece_deadline() set_piece_deadline()

    priority.

    clear_piece_deadlines() removes deadlines on all pieces in the torrent. As if reset_piece_deadline() was called on all pieces.

    -[report issue]
    -
    -

    file_progress()

    + +[report issue]
    +
    +

    file_progress() post_file_progress()

    +void post_file_progress (file_progress_flags_t flags) const;
     std::vector<std::int64_t> file_progress (file_progress_flags_t flags = {}) const;
     void file_progress (std::vector<std::int64_t>& progress, file_progress_flags_t flags = {}) const;
     
    @@ -18472,17 +18713,19 @@

    clear_error()

    If the torrent is in an error state (i.e. torrent_status::error is non-empty), this will clear the error and start the torrent again.

    - + -[report issue]
    -
    -

    trackers() replace_trackers() add_tracker()

    + +[report issue]
    +
    +

    post_trackers() replace_trackers() add_tracker() trackers()

     void add_tracker (announce_entry const&) const;
    -std::vector<announce_entry> trackers () const;
     void replace_trackers (std::vector<announce_entry> const&) const;
    +void post_trackers () const;
    +std::vector<announce_entry> trackers () const;
     
    -

    trackers() will return the list of trackers for this torrent. The +

    trackers() returns the list of trackers for this torrent. The announce entry contains both a string url which specify the announce url for the tracker as well as an int tier, which is specifies the order in which this tracker is tried. If you want @@ -18491,6 +18734,8 @@

    trackers() replace_trackers() add_tracker()

    one returned from trackers() and will replace it. If you want an immediate effect, you have to call force_reannounce(). See announce_entry.

    +

    post_trackers() is the asynchronous version of trackers(). It +will trigger a tracker_list_alert to be posted.

    add_tracker() will look if the specified tracker is already in the set. If it is, it doesn't do anything. If it's not in the current set of trackers, it will insert it in the tier specified in the @@ -18498,14 +18743,14 @@

    trackers() replace_trackers() add_tracker()

    The updated set of trackers will be saved in the resume data, and when a torrent is started with resume data, the trackers from the resume data will replace the original ones.

    - -[report issue]
    -
    -

    add_url_seed() url_seeds() remove_url_seed()

    + +[report issue]
    +
    +

    url_seeds() add_url_seed() remove_url_seed()

    -std::set<std::string> url_seeds () const;
     void add_url_seed (std::string const& url) const;
    +std::set<std::string> url_seeds () const;
     void remove_url_seed (std::string const& url) const;
     

    add_url_seed() adds another url to the torrent's list of url @@ -18517,11 +18762,11 @@

    add_url_seed() url_seeds() remove_url_seed()

    torrent. Note that URLs that fails may be removed automatically from the list.

    See http seeding for more information.

    + - -[report issue]
    -
    -

    remove_http_seed() http_seeds() add_http_seed()

    +[report issue]
    +
    +

    add_http_seed() remove_http_seed() http_seeds()

     std::set<std::string> http_seeds () const;
     void add_http_seed (std::string const& url) const;
    @@ -18531,7 +18776,7 @@ 

    remove_http_seed() http_seeds() add_http_seed()

    they operate on BEP 17 web seeds instead of BEP 19.

    See http seeding for more information.

    [report issue]
    -
    +

    add_extension()

     void add_extension (
    @@ -18557,7 +18802,7 @@ 

    set_metadata()

    otherwise. If the torrent already has metadata, this function will not affect the torrent, and false will be returned.

    [report issue]
    -
    +

    is_valid()

     bool is_valid () const;
    @@ -18575,13 +18820,13 @@ 

    is_valid()

    completes immediately, without blocking on a result from the network thread. Also unlike other functions, it never throws the system_error exception.

    - -[report issue]
    -
    -

    pause() resume()

    + +[report issue]
    +
    +

    resume() pause()

    -void resume () const;
     void pause (pause_flags_t flags = {}) const;
    +void resume () const;
     

    pause(), and resume() will disconnect all peers and reconnect all peers respectively. When a torrent is paused, it will however @@ -18600,16 +18845,16 @@

    pause() resume()

    not auto-managed first. Torrents are auto-managed by default when added to the session. For more information, see queuing.

    - -[report issue]
    -
    -

    set_flags() flags() unset_flags()

    + +[report issue]
    +
    +

    flags() unset_flags() set_flags()

    -void unset_flags (torrent_flags_t flags) const;
    -torrent_flags_t flags () const;
     void set_flags (torrent_flags_t flags) const;
    +torrent_flags_t flags () const;
     void set_flags (torrent_flags_t flags, torrent_flags_t mask) const;
    +void unset_flags (torrent_flags_t flags) const;
     

    sets and gets the torrent state flags. See torrent_flags_t. The set_flags overload that take a mask will affect all @@ -18754,13 +18999,18 @@

    save_resume_data()

    need_save_resume_data()

    +bool need_save_resume_data (resume_data_flags_t flags) const;
     bool need_save_resume_data () const;
     
    -

    This function returns true if any whole chunk has been downloaded -since the torrent was first loaded or since the last time the resume -data was saved. When saving resume data periodically, it makes sense -to skip any torrent which hasn't downloaded anything since the last -time.

    +

    This function returns true if anything that is stored in the resume +data has changed since the last time resume data was saved. +The overload that takes flags let you ask if specific categories +of properties have changed. These flags have the same behavior as in +the save_resume_data() call.

    +

    This is a blocking call. It will wait for a response from +libtorrent's main thread. A way to avoid blocking is to instead +call save_resume_data() directly, specifying the conditions under +which resume data should be saved.

    Note

    A torrent's resume data is considered saved as soon as the @@ -18768,19 +19018,19 @@

    need_save_resume_data()

    alert is received and handled in order for this function to be meaningful.

    + - - -[report issue]
    -
    -

    queue_position_down() queue_position_top() queue_position_up() queue_position_bottom() queue_position()

    + +[report issue]
    +
    +

    queue_position_bottom() queue_position_down() queue_position_up() queue_position() queue_position_top()

    -void queue_position_top () const;
     queue_position_t queue_position () const;
    -void queue_position_bottom () const;
    -void queue_position_up () const;
     void queue_position_down () const;
    +void queue_position_top () const;
    +void queue_position_up () const;
    +void queue_position_bottom () const;
     

    Every torrent that is added is assigned a queue position exactly one greater than the greatest queue position of all existing torrents. @@ -18807,18 +19057,18 @@

    queue_position_set()

    updates the position in the queue for this torrent. The relative order of all other torrents remain intact but their numerical queue position shifts to make space for this torrent's new position

    - -[report issue]
    -
    -

    set_ssl_certificate_buffer() set_ssl_certificate()

    + +[report issue]
    +
    +

    set_ssl_certificate() set_ssl_certificate_buffer()

    +void set_ssl_certificate_buffer (std::string const& certificate
    +      , std::string const& private_key
    +      , std::string const& dh_params);
     void set_ssl_certificate (std::string const& certificate
           , std::string const& private_key
           , std::string const& dh_params
           , std::string const& passphrase = "");
    -void set_ssl_certificate_buffer (std::string const& certificate
    -      , std::string const& private_key
    -      , std::string const& dh_params);
     

    For SSL torrents, use this to specify a path to a .pem file to use as this client's certificate. The certificate must be signed by the @@ -18888,30 +19138,34 @@

    piece_layers()

    v1 torrent (and doesn't have any piece layers) it returns an empty vector. This is a blocking call that will synchronize with the libtorrent network thread.

    -[report issue]
    -
    -

    piece_availability()

    + +[report issue]
    +
    +

    piece_availability() post_piece_availability()

     void piece_availability (std::vector<int>& avail) const;
    +void post_piece_availability () const;
     
    -

    Fills the specified std::vector<int> with the availability for -each piece in this torrent. libtorrent does not keep track of -availability for seeds, so if the torrent is seeding the availability -for all pieces is reported as 0.

    The piece availability is the number of peers that we are connected that has advertised having a particular piece. This is the information that libtorrent uses in order to prefer picking rare pieces.

    - +

    post_piece_availability() will trigger a piece_availability_alert +to be posted.

    +

    piece_availability() fills the specified std::vector<int> +with the availability for each piece in this torrent. libtorrent does +not keep track of availability for seeds, so if the torrent is +seeding the availability for all pieces is reported as 0.

    -[report issue]
    -
    -

    piece_priority() prioritize_pieces() get_piece_priorities()

    + +[report issue]
    +
    +

    prioritize_pieces() piece_priority() get_piece_priorities()

    +download_priority_t piece_priority (piece_index_t index) const;
     std::vector<download_priority_t> get_piece_priorities () const;
    +void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const;
     void prioritize_pieces (std::vector<download_priority_t> const& pieces) const;
     void piece_priority (piece_index_t index, download_priority_t priority) const;
    -void prioritize_pieces (std::vector<std::pair<piece_index_t, download_priority_t>> const& pieces) const;
    -download_priority_t piece_priority (piece_index_t index) const;
     

    These functions are used to set and get the priority of individual pieces. By default all pieces have priority 4. That means that the @@ -18947,10 +19201,10 @@

    piece_priority() prioritize_pieces() get_piece_priorities()

    get_file_priorities() file_priority() prioritize_files()

    +download_priority_t file_priority (file_index_t index) const;
     void prioritize_files (std::vector<download_priority_t> const& files) const;
     void file_priority (file_index_t index, download_priority_t priority) const;
     std::vector<download_priority_t> get_file_priorities () const;
    -download_priority_t file_priority (file_index_t index) const;
     

    index must be in the range [0, number_of_files).

    file_priority() queries or sets the priority of file index.

    @@ -18981,15 +19235,15 @@

    get_file_priorities() file_priority() prioritize_files()

    Moving data from a file into the part file is currently not supported. If a file has its priority set to 0 after it has already been created, it will not be moved into the partfile.

    - -[report issue]
    -
    -

    force_reannounce() force_dht_announce() force_lsd_announce()

    + +[report issue]
    +
    +

    force_dht_announce() force_lsd_announce() force_reannounce()

    -void force_lsd_announce () const;
    -void force_dht_announce () const;
     void force_reannounce (int seconds = 0, int idx = -1, reannounce_flags_t = {}) const;
    +void force_dht_announce () const;
    +void force_lsd_announce () const;
     

    force_reannounce() will force this torrent to do another tracker request, to receive new peers. The seconds argument specifies how @@ -19021,17 +19275,17 @@

    scrape_tracker()

    num_incomplete fields in the torrent_status struct once it completes. When it completes, it will generate a scrape_reply_alert. If it fails, it will generate a scrape_failed_alert.

    - - -[report issue]
    -
    -

    upload_limit() set_upload_limit() set_download_limit() download_limit()

    + + +[report issue]
    +
    +

    set_download_limit() upload_limit() download_limit() set_upload_limit()

     int upload_limit () const;
    +void set_upload_limit (int limit) const;
     int download_limit () const;
     void set_download_limit (int limit) const;
    -void set_upload_limit (int limit) const;
     

    set_upload_limit will limit the upload bandwidth used by this particular torrent to the limit you set. It is given as the number of @@ -19076,8 +19330,8 @@

    clear_peers()

    set_max_uploads() max_uploads()

    -int max_uploads () const;
     void set_max_uploads (int max_uploads) const;
    +int max_uploads () const;
     

    set_max_uploads() sets the maximum number of peers that's unchoked at the same time on this torrent. If you set this to -1, there will be @@ -19090,8 +19344,8 @@

    set_max_uploads() max_uploads()

    max_connections() set_max_connections()

    -int max_connections () const;
     void set_max_connections (int max_connections) const;
    +int max_connections () const;
     

    set_max_connections() sets the maximum number of connection this torrent will open. If all connections are used up, incoming @@ -19154,7 +19408,7 @@

    move_storage()

    when only few pieces have been downloaded, since the files are then allocated with zeros in the destination directory.

    [report issue]
    -
    +

    rename_file()

     void rename_file (file_index_t index, std::string const& new_name) const;
    @@ -19162,13 +19416,13 @@ 

    rename_file()

    Renames the file with the given index asynchronously. The rename operation is complete when either a file_renamed_alert or file_rename_failed_alert is posted.

    - -[report issue]
    -
    -

    info_hashes() info_hash()

    + +[report issue]
    +
    +

    info_hash() info_hashes()

    -sha1_hash info_hash () const;
     info_hash_t info_hashes () const;
    +sha1_hash info_hash () const;
     

    returns the info-hash(es) of the torrent. If this handle is to a torrent that hasn't loaded yet (for instance by being added) by a @@ -19176,15 +19430,15 @@

    info_hashes() info_hash()

    The info_hash() returns the SHA-1 info-hash for v1 torrents and a truncated hash for v2 torrents. For the full v2 info-hash, use info_hashes() instead.

    - -[report issue]
    + +[report issue]
    -

    operator<() operator==() operator!=()

    +

    operator==() operator!=() operator<()

    -bool operator< (const torrent_handle& h) const;
    -bool operator!= (const torrent_handle& h) const;
     bool operator== (const torrent_handle& h) const;
    +bool operator!= (const torrent_handle& h) const;
    +bool operator< (const torrent_handle& h) const;
     

    comparison operators. The order of the torrents is unspecified but stable.

    @@ -19197,7 +19451,7 @@

    id()

    returns a unique identifier for this torrent. It's not a dense index. It's not preserved across sessions.

    [report issue]
    -
    +

    native_handle()

     std::shared_ptr<torrent> native_handle () const;
    @@ -19310,17 +19564,61 @@ 

    in_session()

    [report issue]
    save_info_dict
    the resume data will contain the metadata from the torrent file as -well. This is default for any torrent that's added without a -torrent file (such as a magnet link or a URL).
    +well. This is useful for clients that don't keep .torrent files +around separately, or for torrents that were added via a magnet link.
    [report issue]
    only_if_modified
    -
    if nothing significant has changed in the torrent since the last -time resume data was saved, fail this attempt. Significant changes -primarily include more data having been downloaded, file or piece -priorities having changed etc. If the resume data doesn't need -saving, a save_resume_data_failed_alert is posted with the error -resume_data_not_modified.
    +
    this flag has the same behavior as the combination of: +if_counters_changed | if_download_progress | if_config_changed | +if_state_changed | if_metadata_changed
    +
    +[report issue]
    +
    if_counters_changed
    +
    save resume data if any counters has changed since the last time +resume data was saved. This includes upload/download counters, active +time counters and scrape data. A torrent that is not paused will have +its active time counters incremented continuously.
    +
    +[report issue]
    +
    if_download_progress
    +
    save the resume data if any blocks have been downloaded since the +last time resume data was saved. This includes: +* checking existing files on disk +* downloading a block from a peer
    +
    +[report issue]
    +
    if_config_changed
    +
    save the resume data if configuration options changed since last time +the resume data was saved. This includes: +* file- or piece priorities +* upload- and download rate limits +* change max-uploads (unchoke slots) +* change max connection limit +* enable/disable peer-exchange, local service discovery or DHT +* enable/disable apply IP-filter +* enable/disable auto-managed +* enable/disable share-mode +* enable/disable sequential-mode +* files renamed +* storage moved (save_path changed)
    +
    +[report issue]
    +
    if_state_changed
    +
    save the resume data if torrent state has changed since last time the +resume data was saved. This includes: +* upload mode +* paused state +* super-seeding +* seed-mode
    +
    +[report issue]
    +
    if_metadata_changed
    +
    save the resume data if any metadata changed since the last time +resume data was saved. This includes: +* add/remove web seeds +* add/remove trackers +* receiving metadata for a magnet link
    [report issue]
    ignore_min_interval
    @@ -19362,21 +19660,21 @@

    web_seed_entry

    std::uint8_t type; };
    -[report issue]
    +[report issue]

    operator==()

     bool operator== (web_seed_entry const& e) const;
     

    URL and type comparison

    [report issue]
    -
    +

    operator<()

     bool operator< (web_seed_entry const& e) const;
     

    URL and type less-than comparison

    [report issue]
    -
    +

    enum type_t

    Declared in "libtorrent/torrent_info.hpp"

    @@ -19461,49 +19759,50 @@

    torrent_info

     class torrent_info
     {
    -   torrent_info (std::string const& filename, error_code& ec);
        explicit torrent_info (std::string const& filename);
    -   torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
    -   torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    -   torrent_info (char const* buffer, int size);
    +   explicit torrent_info (span<char const> buffer, from_span_t);
        explicit torrent_info (info_hash_t const& info_hash);
    +   torrent_info (bdecode_node const& torrent_file, error_code& ec);
        torrent_info (char const* buffer, int size, error_code& ec);
    -   explicit torrent_info (span<char const> buffer, from_span_t);
        torrent_info (std::string const& filename, load_torrent_limits const& cfg);
        explicit torrent_info (bdecode_node const& torrent_file);
        torrent_info (torrent_info const& t);
    -   torrent_info (bdecode_node const& torrent_file, error_code& ec);
    +   torrent_info (std::string const& filename, error_code& ec);
        torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    +   torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    +   torrent_info (char const* buffer, int size);
    +   torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
        ~torrent_info ();
    -   file_storage const& files () const;
        file_storage const& orig_files () const;
    +   file_storage const& files () const;
        void rename_file (file_index_t index, std::string const& new_filename);
        void remap_files (file_storage const& f);
    -   std::vector<announce_entry> const& trackers () const;
    +   void add_tracker (std::string const& url, int tier = 0);
        void add_tracker (std::string const& url, int tier
           , announce_entry::tracker_source source);
    -   void add_tracker (std::string const& url, int tier = 0);
        void clear_trackers ();
    +   std::vector<announce_entry> const& trackers () const;
        std::vector<sha1_hash> similar_torrents () const;
        std::vector<std::string> collections () const;
    -   void add_url_seed (std::string const& url
    -      , std::string const& ext_auth = std::string()
    -      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
    +   std::vector<web_seed_entry> const& web_seeds () const;
        void set_web_seeds (std::vector<web_seed_entry> seeds);
        void add_http_seed (std::string const& url
           , std::string const& extern_auth = std::string()
           , web_seed_entry::headers_t const& extra_headers = web_seed_entry::headers_t());
    -   std::vector<web_seed_entry> const& web_seeds () const;
    +   void add_url_seed (std::string const& url
    +      , std::string const& ext_auth = std::string()
    +      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
        std::int64_t total_size () const;
    -   int piece_length () const;
        int num_pieces () const;
    -   piece_index_t last_piece () const;
    -   index_range<piece_index_t> piece_range () const;
    +   int piece_length () const;
    +   int blocks_per_piece () const;
        piece_index_t end_piece () const;
    -   info_hash_t const& info_hashes () const;
    +   index_range<piece_index_t> piece_range () const;
    +   piece_index_t last_piece () const;
        sha1_hash info_hash () const noexcept;
    -   bool v2 () const;
    +   info_hash_t const& info_hashes () const;
        bool v1 () const;
    +   bool v2 () const;
        int num_files () const;
        std::vector<file_slice> map_block (piece_index_t const piece
           , std::int64_t offset, int size) const;
    @@ -19529,22 +19828,22 @@ 

    torrent_info

    void free_piece_layers (); };
    -[report issue]
    +[report issue]

    torrent_info()

    -torrent_info (std::string const& filename, error_code& ec);
     explicit torrent_info (std::string const& filename);
    -torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
    -torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    -torrent_info (char const* buffer, int size);
    +explicit torrent_info (span<char const> buffer, from_span_t);
     explicit torrent_info (info_hash_t const& info_hash);
    +torrent_info (bdecode_node const& torrent_file, error_code& ec);
     torrent_info (char const* buffer, int size, error_code& ec);
    -explicit torrent_info (span<char const> buffer, from_span_t);
     torrent_info (std::string const& filename, load_torrent_limits const& cfg);
     explicit torrent_info (bdecode_node const& torrent_file);
     torrent_info (torrent_info const& t);
    -torrent_info (bdecode_node const& torrent_file, error_code& ec);
    +torrent_info (std::string const& filename, error_code& ec);
     torrent_info (span<char const> buffer, error_code& ec, from_span_t);
    +torrent_info (span<char const> buffer, load_torrent_limits const& cfg, from_span_t);
    +torrent_info (char const* buffer, int size);
    +torrent_info (bdecode_node const& torrent_file, load_torrent_limits const& cfg);
     

    The constructor that takes an info-hash will initialize the info-hash to the given value, but leave all other fields empty. This is used @@ -19575,19 +19874,19 @@

    torrent_info()

    string literals. There is an object in the libtorrent namespace of this type called from_span.

    [report issue]
    -
    +

    ~torrent_info()

     ~torrent_info ();
     

    frees all storage associated with this torrent_info object

    - -[report issue]
    -
    -

    orig_files() files()

    + +[report issue]
    +
    +

    files() orig_files()

    -file_storage const& files () const;
     file_storage const& orig_files () const;
    +file_storage const& files () const;
     

    The file_storage object contains the information on how to map the pieces to files. It is separated from the torrent_info object because @@ -19602,7 +19901,7 @@

    orig_files() files()

    For more information on the file_storage object, see the separate document on how to create torrents.

    [report issue]
    -
    +

    rename_file()

     void rename_file (file_index_t index, std::string const& new_filename);
    @@ -19639,17 +19938,17 @@ 

    remap_files()

    and sizes of the files in the torrent.

    The new specified file_storage must have the exact same size as the current one.

    + - -[report issue]
    -
    -

    trackers() clear_trackers() add_tracker()

    +[report issue]
    +
    +

    add_tracker() trackers() clear_trackers()

    -std::vector<announce_entry> const& trackers () const;
    +void add_tracker (std::string const& url, int tier = 0);
     void add_tracker (std::string const& url, int tier
           , announce_entry::tracker_source source);
    -void add_tracker (std::string const& url, int tier = 0);
     void clear_trackers ();
    +std::vector<announce_entry> const& trackers () const;
     

    add_tracker() adds a tracker to the announce-list. The tier determines the order in which the trackers are to be tried. @@ -19674,21 +19973,21 @@

    collections() similar_torrents()

    "collections" keys in the .torrent file. Both info-hashes and collections from within the info-dict and from outside of it are included.

    - -[report issue]
    -
    -

    add_url_seed() web_seeds() add_http_seed() set_web_seeds()

    + +[report issue]
    +
    +

    web_seeds() add_http_seed() add_url_seed() set_web_seeds()

    -void add_url_seed (std::string const& url
    -      , std::string const& ext_auth = std::string()
    -      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
    +std::vector<web_seed_entry> const& web_seeds () const;
     void set_web_seeds (std::vector<web_seed_entry> seeds);
     void add_http_seed (std::string const& url
           , std::string const& extern_auth = std::string()
           , web_seed_entry::headers_t const& extra_headers = web_seed_entry::headers_t());
    -std::vector<web_seed_entry> const& web_seeds () const;
    +void add_url_seed (std::string const& url
    +      , std::string const& ext_auth = std::string()
    +      , web_seed_entry::headers_t const& ext_headers = web_seed_entry::headers_t());
     

    web_seeds() returns all url seeds and http seeds in the torrent. Each entry is a web_seed_entry and may refer to either a url seed @@ -19706,7 +20005,7 @@

    add_url_seed() web_seeds() add_http_seed() set_web_seeds()

    seed.

    See http seeding for more information.

    [report issue]
    -
    +

    total_size()

     std::int64_t total_size () const;
    @@ -19716,13 +20015,13 @@ 

    total_size()

    size (modulo the last piece possibly being smaller). With pad files, the total size will be larger than the sum of all (regular) file sizes.

    - -[report issue]
    -
    -

    piece_length() num_pieces()

    + +[report issue]
    +
    +

    num_pieces() piece_length()

    -int piece_length () const;
     int num_pieces () const;
    +int piece_length () const;
     

    piece_length() and num_pieces() returns the number of byte for each piece and the total number of pieces, respectively. The @@ -19731,15 +20030,23 @@

    piece_length() num_pieces()

    exact size of that piece. It will always be the same as piece_length() except in the case of the last piece, which may be smaller.

    +[report issue]
    +
    +

    blocks_per_piece()

    +
    +int blocks_per_piece () const;
    +
    +

    returns the number of blocks there are in the typical piece. There +may be fewer in the last piece)

    - -[report issue]
    -
    -

    last_piece() piece_range() end_piece()

    + +[report issue]
    +
    +

    last_piece() end_piece() piece_range()

    -piece_index_t last_piece () const;
    -index_range<piece_index_t> piece_range () const;
     piece_index_t end_piece () const;
    +index_range<piece_index_t> piece_range () const;
    +piece_index_t last_piece () const;
     

    last_piece() returns the index to the last piece in the torrent and end_piece() returns the index to the one-past-end piece in the @@ -19747,13 +20054,13 @@

    last_piece() piece_range() end_piece()

    piece_range() returns an implementation-defined type that can be used as the container in a range-for loop. Where the values are the indices of all pieces in the file_storage.

    - -[report issue]
    -
    -

    info_hashes() info_hash()

    + +[report issue]
    +
    +

    info_hash() info_hashes()

    -info_hash_t const& info_hashes () const;
     sha1_hash info_hash () const noexcept;
    +info_hash_t const& info_hashes () const;
     

    returns the info-hash of the torrent. For BitTorrent v2 support, use info_hashes() to get an object that may hold both a v1 and v2 @@ -19763,14 +20070,14 @@

    info_hashes() info_hash()

    v1() v2()

    -bool v2 () const;
     bool v1 () const;
    +bool v2 () const;
     

    returns whether this torrent has v1 and/or v2 metadata, respectively. Hybrid torrents have both. These are shortcuts for info_hashes().has_v1() and info_hashes().has_v2() calls.

    [report issue]
    -
    +

    num_files()

     int num_files () const;
    @@ -19779,7 +20086,7 @@ 

    num_files()

    with the file_path(), file_size()-family of functions to access files using indices.

    [report issue]
    -
    +

    map_block()

     std::vector<file_slice> map_block (piece_index_t const piece
    @@ -19789,7 +20096,7 @@ 

    map_block()

    and a size (in bytes) into the corresponding files with offsets where that data for that piece is supposed to be stored. See file_slice.

    [report issue]
    -
    +

    map_file()

     peer_request map_file (file_index_t const file, std::int64_t offset, int size) const;
    @@ -19811,7 +20118,7 @@ 

    ssl_cert()

    torrent. Otherwise returns an empty string. The certificate is the public certificate in x509 format.

    [report issue]
    -
    +

    is_valid()

     bool is_valid () const;
    @@ -19838,7 +20145,7 @@ 

    is_i2p()

    torrents disable the DHT and local peer discovery as well as talking to peers over anything other than the i2p network.

    [report issue]
    -
    +

    piece_size()

     int piece_size (piece_index_t index) const;
    @@ -19894,7 +20201,7 @@ 

    comment()

    there's no comment, it will return an empty string. comment contains UTF-8 encoded string.

    [report issue]
    -
    +

    nodes()

     std::vector<std::pair<std::string, int>> const& nodes () const;
    @@ -19902,7 +20209,7 @@ 

    nodes()

    If this torrent contains any DHT nodes, they are put in this vector in their original form (host name and port number).

    [report issue]
    -
    +

    add_node()

     void add_node (std::pair<std::string, int> const& node);
    @@ -20008,7 +20315,7 @@ 

    dht_storage_counters

    std::int32_t mutable_data = 0; };
    -[report issue]
    +[report issue]

    reset()

     void reset ();
    @@ -20207,7 +20514,7 @@ 

    get_infohashes_sample()

    and modify the actual sample to put in item

    returns the number of info-hashes in the sample.

    [report issue]
    -
    +

    tick()

     virtual void tick () = 0;
    @@ -20217,7 +20524,7 @@ 

    tick()

    Use this functions for expire peers or items or any other storage cleanup.

    [report issue]
    -
    +

    counters()

     virtual dht_storage_counters counters () const = 0;
    @@ -20276,14 +20583,14 @@ 

    announce_flags_t

    read_resume_data()

    Declared in "libtorrent/read_resume_data.hpp"

    -add_torrent_params read_resume_data (bdecode_node const& rd
    -   , int piece_limit = 0x200000);
     add_torrent_params read_resume_data (span<char const> buffer
        , error_code& ec, load_torrent_limits const& cfg = {});
     add_torrent_params read_resume_data (bdecode_node const& rd
    -   , error_code& ec, int piece_limit = 0x200000);
    +   , int piece_limit = 0x200000);
     add_torrent_params read_resume_data (span<char const> buffer
        , load_torrent_limits const& cfg = {});
    +add_torrent_params read_resume_data (bdecode_node const& rd
    +   , error_code& ec, int piece_limit = 0x200000);
     

    these functions are used to parse resume data and populate the appropriate fields in an add_torrent_params object. This object can then be used to add @@ -20305,8 +20612,8 @@

    read_resume_data()

    write_resume_data() write_resume_data_buf()

    Declared in "libtorrent/write_resume_data.hpp"

    -entry write_resume_data (add_torrent_params const& atp);
     std::vector<char> write_resume_data_buf (add_torrent_params const& atp);
    +entry write_resume_data (add_torrent_params const& atp);
     

    this function turns the resume data in an add_torrent_params object into a bencoded structure

    @@ -20317,9 +20624,9 @@

    write_torrent_file() write_torrent_file_buf()

    Declared in "libtorrent/write_resume_data.hpp"

     entry write_torrent_file (add_torrent_params const& atp, write_torrent_flags_t flags);
    -entry write_torrent_file (add_torrent_params const& atp);
     std::vector<char> write_torrent_file_buf (add_torrent_params const& atp
        , write_torrent_flags_t flags);
    +entry write_torrent_file (add_torrent_params const& atp);
     

    writes only the fields to create a .torrent file. This function may fail with a std::system_error exception if:

    @@ -20399,10 +20706,10 @@

    ed25519_verify()

    ed25519_add_scalar()

    Declared in "libtorrent/kademlia/ed25519.hpp"

    -secret_key ed25519_add_scalar (secret_key const& sk
    -   , std::array<char, 32> const& scalar);
     public_key ed25519_add_scalar (public_key const& pk
        , std::array<char, 32> const& scalar);
    +secret_key ed25519_add_scalar (secret_key const& sk
    +   , std::array<char, 32> const& scalar);
     

    Adds a scalar to the given key pair where scalar is a 32 byte buffer (possibly generated with ed25519_create_seed), generating a new key pair.

    diff --git a/3rd/libtorrent-rasterbar/docs/streaming.html b/3rd/libtorrent-rasterbar/docs/streaming.html index 2d05e06c..71fe7332 100644 --- a/3rd/libtorrent-rasterbar/docs/streaming.html +++ b/3rd/libtorrent-rasterbar/docs/streaming.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,7 +25,7 @@

    Streaming implementation

    - +
    Version:2.0.8
    2.0.9

    This documents describes the algorithm libtorrent uses to satisfy time critical diff --git a/3rd/libtorrent-rasterbar/docs/todo.html b/3rd/libtorrent-rasterbar/docs/todo.html index f2d08d8e..f6601c9e 100644 --- a/3rd/libtorrent-rasterbar/docs/todo.html +++ b/3rd/libtorrent-rasterbar/docs/todo.html @@ -25,7 +25,7 @@

    libtorrent todo-list

    39 important 50 relevant 4 feasible -191 notes +192 notes
    relevance 4../test/test_dht.cpp:1250pass in the actual salt as a parameter
    relevance 3../src/torrent.cpp:407we could probably get away with just saving a few fields here
    relevance 3../src/torrent.cpp:418we could probably get away with just saving a few fields here
    relevance 3../src/torrent.cpp:690assert there are no outstanding async operations on this torrent
    relevance 3../src/torrent.cpp:714assert there are no outstanding async operations on this torrent
    relevance 3../src/torrent.cpp:1280there's some duplication between this function and peer_connection::incoming_piece(). is there a way to merge something?
    relevance 3../src/torrent.cpp:1326there's some duplication between this function and peer_connection::incoming_piece(). is there a way to merge something?
    relevance 3../src/torrent.cpp:3841this could probably be pulled out into a free function
    relevance 3../src/torrent.cpp:3951this could probably be pulled out into a free function
    relevance 3../src/torrent.cpp:4764should this alert have an error code in it?
    relevance 3../src/torrent.cpp:4886should this alert have an error code in it?
    relevance 3../src/torrent.cpp:4832this should return optional<>. piece index -1 should not be allowed
    relevance 3../src/torrent.cpp:4956this should return optional<>. piece index -1 should not be allowed
    relevance 3../src/web_peer_connection.cpp:413do we really need a special case here? wouldn't the multi-file case handle single file torrents correctly too?
    relevance 3../src/web_peer_connection.cpp:419do we really need a special case here? wouldn't the multi-file case handle single file torrents correctly too?
    relevance 3../src/web_peer_connection.cpp:498file_index_t should not allow negative values
    relevance 3../src/web_peer_connection.cpp:504file_index_t should not allow negative values
    relevance 3../src/web_peer_connection.cpp:677this could be made more efficient for the case when we use an HTTP proxy. Then we wouldn't need to add new web seeds to the torrent, we could just make the redirect table contain full URLs.
    relevance 3../src/web_peer_connection.cpp:695this could be made more efficient for the case when we use an HTTP proxy. Then we wouldn't need to add new web seeds to the torrent, we could just make the redirect table contain full URLs.
    relevance 3../src/peer_connection.cpp:3102instead of having to ask the torrent whether it's in graceful pause mode or not, the peers should keep that state (and the torrent should update them when it enters graceful pause). When a peer enters graceful pause mode, it should cancel all outstanding requests and clear its request queue.
    relevance 3../src/peer_connection.cpp:3119instead of having to ask the torrent whether it's in graceful pause mode or not, the peers should keep that state (and the torrent should update them when it enters graceful pause). When a peer enters graceful pause mode, it should cancel all outstanding requests and clear its request queue.
    relevance 3../src/peer_connection.cpp:3991once peers are properly put in graceful pause mode, they can cancel all outstanding requests and this test can be removed.
    relevance 3../src/peer_connection.cpp:4027once peers are properly put in graceful pause mode, they can cancel all outstanding requests and this test can be removed.
    relevance 3../src/peer_connection.cpp:4671new_piece should be an optional. piece index -1 should not be allowed
    relevance 3../src/peer_connection.cpp:4713new_piece should be an optional. piece index -1 should not be allowed
    relevance 3../src/session_impl.cpp:1137closing the udp sockets here means that the uTP connections cannot be closed gracefully
    relevance 3../src/session_impl.cpp:1139closing the udp sockets here means that the uTP connections cannot be closed gracefully
    relevance 3../src/session_impl.cpp:1597the logic in this if-block should be factored out into a separate function. At least most of it
    relevance 3../src/session_impl.cpp:1633the logic in this if-block should be factored out into a separate function. At least most of it
    relevance 3../src/session_impl.cpp:2562it would be neat if the utp socket manager would handle ICMP errors too
    relevance 3../src/session_impl.cpp:2601it would be neat if the utp socket manager would handle ICMP errors too
    relevance 3../src/session_impl.cpp:4104it would probably make sense to have a separate list of peers that are eligible for optimistic unchoke, similar to the torrents perhaps this could even iterate over the pool allocators of torrent_peer objects. It could probably be done in a single pass and collect the n best candidates. maybe just a queue of peers would make even more sense, just pick the next peer in the queue for unchoking. It would be O(1).
    relevance 3../src/session_impl.cpp:4143it would probably make sense to have a separate list of peers that are eligible for optimistic unchoke, similar to the torrents perhaps this could even iterate over the pool allocators of torrent_peer objects. It could probably be done in a single pass and collect the n best candidates. maybe just a queue of peers would make even more sense, just pick the next peer in the queue for unchoking. It would be O(1).
    relevance 3../src/session_impl.cpp:4127peers should know whether their torrent is paused or not, instead of having to ask it over and over again
    relevance 3../src/session_impl.cpp:4166peers should know whether their torrent is paused or not, instead of having to ask it over and over again
    relevance 3../src/session_impl.cpp:4373there should be a pre-calculated list of all peers eligible for unchoking
    relevance 3../src/session_impl.cpp:4412there should be a pre-calculated list of all peers eligible for unchoking
    relevance 3../src/session_impl.cpp:6086use public_key here instead of std::array
    relevance 3../src/session_impl.cpp:6121use public_key here instead of std::array
    relevance 3../include/libtorrent/torrent.hpp:1409factor out predictive pieces and all operations on it into a separate class (to use as memeber here instead)
    relevance 3../include/libtorrent/torrent.hpp:1438factor out predictive pieces and all operations on it into a separate class (to use as memeber here instead)
    relevance 3../include/libtorrent/torrent.hpp:1469factor out the links (as well as update_list() to a separate class that torrent can inherit)
    relevance 3../include/libtorrent/torrent.hpp:1498factor out the links (as well as update_list() to a separate class that torrent can inherit)
    relevance 3../include/libtorrent/web_peer_connection.hpp:118if we make this be a disk_buffer_holder instead we would save a copy use allocate_disk_receive_buffer and release_disk_receive_buffer
    relevance 3../include/libtorrent/web_peer_connection.hpp:119if we make this be a disk_buffer_holder instead we would save a copy use allocate_disk_receive_buffer and release_disk_receive_buffer
    relevance 3../include/libtorrent/torrent_handle.hpp:507unify url_seed and http_seed with just web_seed, using the web_seed_entry.
    relevance 3../include/libtorrent/torrent_handle.hpp:535unify url_seed and http_seed with just web_seed, using the web_seed_entry.
    relevance 2../test/test_piece_picker.cpp:2825test picking with partial pieces and other peers present so that both backup_pieces and backup_pieces2 are used
    relevance 2../src/torrent.cpp:492post alert
    relevance 2../src/torrent.cpp:503post alert
    relevance 2../src/torrent.cpp:1796add a unit test where we don't have metadata, connect to a peer that sends a bitfield that's too large, then we get the metadata
    relevance 2../src/torrent.cpp:1842add a unit test where we don't have metadata, connect to a peer that sends a bitfield that's too large, then we get the metadata
    relevance 2../src/torrent.cpp:4351use chrono type for time duration
    relevance 2../src/torrent.cpp:4473use chrono type for time duration
    relevance 2../src/torrent.cpp:4776abort lookups this torrent has made via the session host resolver interface
    relevance 2../src/torrent.cpp:4900abort lookups this torrent has made via the session host resolver interface
    relevance 2../src/torrent.cpp:7830if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)
    relevance 2../src/torrent.cpp:8008if peer is a really good peer, maybe we shouldn't disconnect it perhaps this logic should be disabled if we have too many idle peers (with some definition of idle)
    relevance 2../src/web_peer_connection.cpp:620just make this peer not have the pieces associated with the file we just requested. Only when it doesn't have any of the file do the following pad files will make it complicated
    relevance 2../src/web_peer_connection.cpp:626just make this peer not have the pieces associated with the file we just requested. Only when it doesn't have any of the file do the following pad files will make it complicated
    relevance 2../src/peer_connection.cpp:2531this should probably be based on time instead of number of request messages. For a very high throughput connection, 300 may be a legitimate number of requests to have in flight when getting choked
    relevance 2../src/peer_connection.cpp:2548this should probably be based on time instead of number of request messages. For a very high throughput connection, 300 may be a legitimate number of requests to have in flight when getting choked
    relevance 2../src/peer_connection.cpp:3276since we throw away the queue entry once we issue the disk job, this may happen. Instead, we should keep the queue entry around, mark it as having been requested from disk and once the disk job comes back, discard it if it has been cancelled. Maybe even be able to cancel disk jobs?
    relevance 2../src/peer_connection.cpp:3293since we throw away the queue entry once we issue the disk job, this may happen. Instead, we should keep the queue entry around, mark it as having been requested from disk and once the disk job comes back, discard it if it has been cancelled. Maybe even be able to cancel disk jobs?
    relevance 2../src/peer_connection.cpp:4916use a deadline_timer for timeouts. Don't rely on second_tick()! Hook this up to connect timeout as well. This would improve performance because of less work in second_tick(), and might let use remove ticking entirely eventually
    relevance 2../src/peer_connection.cpp:4958use a deadline_timer for timeouts. Don't rely on second_tick()! Hook this up to connect timeout as well. This would improve performance because of less work in second_tick(), and might let use remove ticking entirely eventually
    relevance 2../src/peer_list.cpp:536it would be nice if there was a way to iterate over these torrent_peer objects in the order they are allocated in the pool instead. It would probably be more efficient
    relevance 2../src/peer_list.cpp:537it would be nice if there was a way to iterate over these torrent_peer objects in the order they are allocated in the pool instead. It would probably be more efficient
    relevance 2../src/alert.cpp:2020the salt here is allocated on the heap. It would be nice to allocate in the stack_allocator
    relevance 2../src/alert.cpp:2021the salt here is allocated on the heap. It would be nice to allocate in the stack_allocator
    relevance 2../src/escape_string.cpp:192this should probably be moved into string_util.cpp
    relevance 2../src/escape_string.cpp:194this should probably be moved into string_util.cpp
    relevance 2../src/http_tracker_connection.cpp:469returning a bool here is redundant. Instead this function should return the peer_entry
    relevance 2../src/http_tracker_connection.cpp:479returning a bool here is redundant. Instead this function should return the peer_entry
    relevance 2../src/session_impl.cpp:595is there a reason not to move all of this into init()? and just post it to the io_context?
    relevance 2../src/session_impl.cpp:598is there a reason not to move all of this into init()? and just post it to the io_context?
    relevance 2../src/session_impl.cpp:757the ip filter should probably be saved here too
    relevance 2../src/session_impl.cpp:760the ip filter should probably be saved here too
    relevance 2../src/session_impl.cpp:3831make a list for torrents that want to be announced on the DHT so we don't have to loop over all torrents, just to find the ones that want to announce
    relevance 2../src/session_impl.cpp:3870make a list for torrents that want to be announced on the DHT so we don't have to loop over all torrents, just to find the ones that want to announce
    relevance 2../src/session_impl.cpp:5468this function should be removed and users need to deal with the more generic case of having multiple listen ports
    relevance 2../src/session_impl.cpp:5503this function should be removed and users need to deal with the more generic case of having multiple listen ports
    relevance 2../src/session_impl.cpp:5508this function should be removed and users need to deal with the more generic case of having multiple ssl ports
    relevance 2../src/session_impl.cpp:5543this function should be removed and users need to deal with the more generic case of having multiple ssl ports
    relevance 2../src/session_impl.cpp:6339this should be factored into the udp socket, so we only have the code once
    relevance 2../src/session_impl.cpp:6375this should be factored into the udp socket, so we only have the code once
    relevance 2../src/kademlia/node.cpp:681it would be nice to have a bias towards node-id prefixes that are missing in the bucket
    relevance 2../src/kademlia/node.cpp:684it would be nice to have a bias towards node-id prefixes that are missing in the bucket
    relevance 2../src/kademlia/node.cpp:753use the non deprecated function instead of this one
    relevance 2../src/kademlia/node.cpp:757use the non deprecated function instead of this one
    relevance 2../include/libtorrent/peer_connection.hpp:990this should really be a circular buffer
    relevance 2../include/libtorrent/peer_connection.hpp:996this should really be a circular buffer
    relevance 2../include/libtorrent/peer_connection.hpp:1080rename this target queue size
    relevance 2../include/libtorrent/peer_connection.hpp:1086rename this target queue size
    relevance 1../src/torrent.cpp:1095make this depend on the error and on the filesystem the files are being downloaded to. If the error is no_space_left_on_device and the filesystem doesn't support sparse files, only zero the priorities of the pieces that are at the tails of all files, leaving everything up to the highest written piece in each file
    relevance 1../src/torrent.cpp:1125make this depend on the error and on the filesystem the files are being downloaded to. If the error is no_space_left_on_device and the filesystem doesn't support sparse files, only zero the priorities of the pieces that are at the tails of all files, leaving everything up to the highest written piece in each file
    relevance 1../src/torrent.cpp:8193should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though
    relevance 1../src/torrent.cpp:8371should disconnect all peers that have the pieces we have not just seeds. It would be pretty expensive to check all pieces for all peers though
    relevance 1../src/session_impl.cpp:5660report the proper address of the router as the source IP of this vote of our external address, instead of the empty address
    relevance 1../src/session_impl.cpp:5695report the proper address of the router as the source IP of this vote of our external address, instead of the empty address
    relevance 0../test/test_dht.cpp:4080test obfuscated_get_peers
    relevance 0../test/test_dht.cpp:4081test obfuscated_get_peers
    relevance 0../test/test_resume.cpp:567test what happens when loading a resume file with both piece priorities and file priorities (file prio should take precedence)
    relevance 0../test/test_resume.cpp:582test what happens when loading a resume file with both piece priorities and file priorities (file prio should take precedence)
    relevance 0../test/test_resume.cpp:570make sure a resume file only ever contain file priorities OR piece priorities. Never both.
    relevance 0../test/test_resume.cpp:585make sure a resume file only ever contain file priorities OR piece priorities. Never both.
    relevance 0../test/test_resume.cpp:573generally save
    relevance 0../test/test_resume.cpp:588generally save
    relevance 0../test/test_resume.cpp:896test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance
    relevance 0../test/test_resume.cpp:911test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance
    relevance 0../test/test_resume.cpp:1668test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance
    relevance 0../test/test_resume.cpp:1683test all other resume flags here too. This would require returning more than just the torrent_status from test_resume_flags. Also http seeds and trackers for instance
    relevance 0../test/test_torrent_info.cpp:452test remap_files
    relevance 0../test/test_torrent_info.cpp:453torrent with 'p' (padfile) attribute
    relevance 0../test/test_torrent_info.cpp:454torrent with 'h' (hidden) attribute
    relevance 0../test/test_torrent_info.cpp:455torrent with 'x' (executable) attribute
    relevance 0../test/test_torrent_info.cpp:456torrent with 'l' (symlink) attribute
    relevance 0../test/test_torrent_info.cpp:457torrent 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)
    relevance 0../test/test_torrent_info.cpp:455test remap_files
    relevance 0../test/test_torrent_info.cpp:456torrent with 'p' (padfile) attribute
    relevance 0../test/test_torrent_info.cpp:457torrent with 'h' (hidden) attribute
    relevance 0../test/test_torrent_info.cpp:458torrent with 'x' (executable) attribute
    relevance 0../test/test_torrent_info.cpp:459torrent with 'l' (symlink) attribute
    relevance 0../test/test_torrent_info.cpp:460torrent 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)
    relevance 0../test/test_torrent_info.cpp:460torrents with a zero-length name
    relevance 0../test/test_torrent_info.cpp:461torrent with a non-dictionary info-section
    relevance 0../test/test_torrent_info.cpp:462torrents with DHT nodes
    relevance 0../test/test_torrent_info.cpp:463torrent with url-list as a single string
    relevance 0../test/test_torrent_info.cpp:464torrent with http seed as a single string
    relevance 0../test/test_torrent_info.cpp:465torrent with a comment
    relevance 0../test/test_torrent_info.cpp:466torrent with an SSL cert
    relevance 0../test/test_torrent_info.cpp:467torrent with attributes (executable and hidden)
    relevance 0../test/test_torrent_info.cpp:468torrent_info constructor that takes an invalid bencoded buffer
    relevance 0../test/test_torrent_info.cpp:469verify_encoding with a string that triggers character replacement
    relevance 0../test/test_torrent_info.cpp:463torrents with a zero-length name
    relevance 0../test/test_torrent_info.cpp:464torrent with a non-dictionary info-section
    relevance 0../test/test_torrent_info.cpp:465torrents with DHT nodes
    relevance 0../test/test_torrent_info.cpp:466torrent with url-list as a single string
    relevance 0../test/test_torrent_info.cpp:467torrent with http seed as a single string
    relevance 0../test/test_torrent_info.cpp:468torrent with a comment
    relevance 0../test/test_torrent_info.cpp:469torrent with an SSL cert
    relevance 0../test/test_torrent_info.cpp:470torrent with attributes (executable and hidden)
    relevance 0../test/test_torrent_info.cpp:471torrent_info constructor that takes an invalid bencoded buffer
    relevance 0../test/test_torrent_info.cpp:472verify_encoding with a string that triggers character replacement
    relevance 0../test/test_ssl.cpp:399test using a signed certificate with the wrong info-hash in DN
    relevance 0../test/test_ssl.cpp:407test using a signed certificate with the wrong info-hash in DN
    relevance 0../test/test_ssl.cpp:501also test using a hash that refers to a valid torrent but that differs from the SNI hash
    relevance 0../test/test_ssl.cpp:509also test using a hash that refers to a valid torrent but that differs from the SNI hash
    relevance 0../test/test_merkle_tree.cpp:935add test for load_piece_layer()
    relevance 0../test/test_merkle_tree.cpp:936add test for add_hashes() with an odd number of blocks
    relevance 0../test/test_merkle_tree.cpp:937add test for set_block() (setting the last block) with an odd number of blocks
    relevance 0../test/test_merkle_tree.cpp:938add test for load_piece_layer()
    relevance 0../test/test_merkle_tree.cpp:939add test for add_hashes() with an odd number of blocks
    relevance 0../test/test_merkle_tree.cpp:940add test for set_block() (setting the last block) with an odd number of blocks
    relevance 0../test/test_peer_list.cpp:968test erasing peers
    relevance 0../test/test_peer_list.cpp:969test update_peer_port with allow_multiple_connections_per_ip and without
    relevance 0../test/test_peer_list.cpp:970test add i2p peers
    relevance 0../test/test_peer_list.cpp:971test allow_i2p_mixed
    relevance 0../test/test_peer_list.cpp:972test insert_peer failing with all error conditions
    relevance 0../test/test_peer_list.cpp:973test IPv6
    relevance 0../test/test_peer_list.cpp:974test connect_to_peer() failing
    relevance 0../test/test_peer_list.cpp:975test connection_closed
    relevance 0../test/test_peer_list.cpp:976connect candidates recalculation when incrementing failcount
    relevance 0../test/test_file_storage.cpp:1208test file attributes
    relevance 0../test/test_file_storage.cpp:1209test symlinks
    relevance 0../test/test_upnp.cpp:156store the log and verify that some key messages are there
    relevance 0../test/test_peer_list.cpp:1209test erasing peers
    relevance 0../test/test_peer_list.cpp:1210test update_peer_port with allow_multiple_connections_per_ip and without
    relevance 0../test/test_peer_list.cpp:1211test add i2p peers
    relevance 0../test/test_peer_list.cpp:1212test allow_i2p_mixed
    relevance 0../test/test_peer_list.cpp:1213test insert_peer failing with all error conditions
    relevance 0../test/test_peer_list.cpp:1214test IPv6
    relevance 0../test/test_peer_list.cpp:1215test connect_to_peer() failing
    relevance 0../test/test_peer_list.cpp:1216test connection_closed
    relevance 0../test/test_peer_list.cpp:1217connect candidates recalculation when incrementing failcount
    relevance 0../test/test_file_storage.cpp:1208test file attributes
    relevance 0../test/test_file_storage.cpp:1209test symlinks
    relevance 0../test/test_upnp.cpp:156store the log and verify that some key messages are there
    relevance 0../src/torrent.cpp:1895this could be optimized by looking up which files are complete and just look at those
    relevance 0../src/torrent.cpp:1941this could be optimized by looking up which files are complete and just look at those
    relevance 0../src/torrent.cpp:1908this could be optimized by looking up which files are complete and just look at those
    relevance 0../src/torrent.cpp:1954this could be optimized by looking up which files are complete and just look at those
    relevance 0../src/torrent.cpp:2667this pattern is repeated in a few places. Factor this into a function and generalize the concept of a torrent having a dedicated listen port
    relevance 0../src/torrent.cpp:2715this pattern is repeated in a few places. Factor this into a function and generalize the concept of a torrent having a dedicated listen port
    relevance 0../src/torrent.cpp:3760add one peer per IP the hostname resolves to
    relevance 0../src/torrent.cpp:3870add one peer per IP the hostname resolves to
    relevance 0../src/torrent.cpp:4440only do this if the piece size > 1 blocks This is a v2 torrent so we can request get block level hashes.
    relevance 0../src/torrent.cpp:4562only do this if the piece size > 1 blocks This is a v2 torrent so we can request get block level hashes.
    relevance 0../src/torrent.cpp:7331come up with a better way of doing this, instead of an immediately invoked lambda expression.
    relevance 0../src/torrent.cpp:7501come up with a better way of doing this, instead of an immediately invoked lambda expression.
    relevance 0../src/torrent.cpp:8913perhaps 0 should actially mean 0
    relevance 0../src/torrent.cpp:9091perhaps 0 should actially mean 0
    relevance 0../src/torrent.cpp:8929perhaps 0 should actially mean 0
    relevance 0../src/torrent.cpp:9108perhaps 0 should actially mean 0
    relevance 0../src/torrent.cpp:9226add a flag to ignore stats, and only care about resume data for content. For unchanged files, don't trigger a load of the metadata just to save an empty resume data file
    relevance 0../src/torrent.cpp:10825instead of resorting the whole list, insert the peers directly into the right place
    relevance 0../src/torrent.cpp:11037instead of resorting the whole list, insert the peers directly into the right place
    relevance 0../src/merkle_tree.cpp:111in C++20, use std::identity
    relevance 0../src/merkle_tree.cpp:110in C++20, use std::identity
    relevance 0../src/merkle_tree.cpp:320this can be optimized by using m_tree as storage to fill this tree into, and then clear it if the hashes fail
    relevance 0../src/merkle_tree.cpp:319this can be optimized by using m_tree as storage to fill this tree into, and then clear it if the hashes fail
    relevance 0../src/merkle_tree.cpp:368a piece outside of this range may also fail, if one of the uncle hashes is at the layer right above the block hashes
    relevance 0../src/merkle_tree.cpp:367a piece outside of this range may also fail, if one of the uncle hashes is at the layer right above the block hashes
    relevance 0../src/merkle_tree.cpp:448instead of overwriting the root and comparing it against hashes[], write a functions that *validates* a tree by just filling it up to the level below the root and then validates it.
    relevance 0../src/merkle_tree.cpp:447instead of overwriting the root and comparing it against hashes[], write a functions that *validates* a tree by just filling it up to the level below the root and then validates it.
    relevance 0../src/merkle_tree.cpp:472this could be done more efficiently if bitfield had a function to set a range of bits
    relevance 0../src/merkle_tree.cpp:471this could be done more efficiently if bitfield had a function to set a range of bits
    relevance 0../src/merkle_tree.cpp:513use structured binding in C++17
    relevance 0../src/merkle_tree.cpp:514use structured binding in C++17
    relevance 0../src/merkle_tree.cpp:553this could be done more efficiently if bitfield had a function to set a range of bits
    relevance 0../src/merkle_tree.cpp:539this could be done more efficiently if bitfield had a function to set a range of bits
    relevance 0../src/ip_notifier.cpp:41simulator support
    relevance 0../src/ip_notifier.cpp:41simulator support
    relevance 0../src/peer_connection.cpp:1090this should be the global download rate
    relevance 0../src/peer_connection.cpp:1091this should be the global download rate
    relevance 0../src/peer_connection.cpp:3503sort the allowed fast set in priority order
    relevance 0../src/peer_connection.cpp:3520sort the allowed fast set in priority order
    relevance 0../src/part_file.cpp:300what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal
    relevance 0../src/part_file.cpp:300what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal
    relevance 0../src/part_file.cpp:412instead of rebuilding the whole file header and flushing it, update the slot entries as we go
    relevance 0../src/part_file.cpp:412instead of rebuilding the whole file header and flushing it, update the slot entries as we go
    relevance 0../src/torrent_info.cpp:869this should be considered a failure, and the .torrent file rejected
    relevance 0../src/torrent_info.cpp:875this should be considered a failure, and the .torrent file rejected
    relevance 0../src/settings_pack.cpp:305deprecate this
    relevance 0../src/settings_pack.cpp:305deprecate this
    relevance 0../src/settings_pack.cpp:585it would be nice to reserve() these vectors up front
    relevance 0../src/settings_pack.cpp:589it would be nice to reserve() these vectors up front
    relevance 0../src/packet_buffer.cpp:157use compare_less_wrap for this comparison as well
    relevance 0../src/packet_buffer.cpp:157use compare_less_wrap for this comparison as well
    relevance 0../src/performance_counters.cpp:40move stats_counter_t out of counters
    relevance 0../src/performance_counters.cpp:41should bittorrent keep-alive messages have a counter too?
    relevance 0../src/performance_counters.cpp:42It would be nice if this could be an internal type. default_disk_constructor depends on it now
    relevance 0../src/performance_counters.cpp:40move stats_counter_t out of counters
    relevance 0../src/performance_counters.cpp:41should bittorrent keep-alive messages have a counter too?
    relevance 0../src/performance_counters.cpp:42It would be nice if this could be an internal type. default_disk_constructor depends on it now
    relevance 0../src/hash_picker.cpp:311use structured bindings in C++17
    relevance 0../src/hash_picker.cpp:309use structured bindings in C++17
    relevance 0../src/web_connection_base.cpp:72introduce a web-seed default class which has a low download priority
    relevance 0../src/web_connection_base.cpp:72introduce a web-seed default class which has a low download priority
    relevance 0../src/enum_net.cpp:144in C++17, use __has_include for this. Other operating systems are likely to require this as well
    relevance 0../src/enum_net.cpp:144in C++17, use __has_include for this. Other operating systems are likely to require this as well
    relevance 0../src/enum_net.cpp:268if we get here, the caller still assumes the error code is reported via errno
    relevance 0../src/enum_net.cpp:268if we get here, the caller still assumes the error code is reported via errno
    relevance 0../src/enum_net.cpp:274if we get here, the caller still assumes the error code is reported via errno
    relevance 0../src/enum_net.cpp:274if we get here, the caller still assumes the error code is reported via errno
    relevance 0../src/utp_socket_manager.cpp:199this should not be heap allocated, sockets should be movable
    relevance 0../src/utp_socket_manager.cpp:204this should not be heap allocated, sockets should be movable
    relevance 0../src/ut_metadata.cpp:281we really need to increment the refcounter on the torrent while this buffer is still in the peer's send buffer
    relevance 0../src/ut_metadata.cpp:281we really need to increment the refcounter on the torrent while this buffer is still in the peer's send buffer
    relevance 0../src/file_storage.cpp:452maybe it would be nice to have a better index here
    relevance 0../src/file_storage.cpp:457maybe it would be nice to have a better index here
    relevance 0../src/file_storage.cpp:1237this would be more efficient if m_paths was sorted first, such that a lower path index always meant sorted-before
    relevance 0../src/file_storage.cpp:1242this would be more efficient if m_paths was sorted first, such that a lower path index always meant sorted-before
    relevance 0../src/file_storage.cpp:1340in C++17 this could be string_view
    relevance 0../src/file_storage.cpp:1345in C++17 this could be string_view
    relevance 0../src/random.cpp:141improve calling RAND_bytes multiple times, using fallback for now
    relevance 0../src/random.cpp:141improve calling RAND_bytes multiple times, using fallback for now
    relevance 0../src/mmap_disk_io.cpp:578in the future, propagate exceptions back to the handlers
    relevance 0../src/mmap_disk_io.cpp:578in the future, propagate exceptions back to the handlers
    relevance 0../src/mmap_disk_io.cpp:1017this is potentially very expensive. One way to solve it would be to have a fence for just this one piece. but it hardly seems worth the complexity and cost just for the edge case of receiving a corrupt piece
    relevance 0../src/mmap_disk_io.cpp:1017this is potentially very expensive. One way to solve it would be to have a fence for just this one piece. but it hardly seems worth the complexity and cost just for the edge case of receiving a corrupt piece
    relevance 0../src/mmap_disk_io.cpp:1022Perhaps the job queue could be traversed and all jobs for this piece could be cancelled. If there are no threads currently writing to this piece, we could skip the fence alltogether
    relevance 0../src/mmap_disk_io.cpp:1022Perhaps the job queue could be traversed and all jobs for this piece could be cancelled. If there are no threads currently writing to this piece, we could skip the fence alltogether
    relevance 0../src/session.cpp:539In C++17. use if constexpr instead
    relevance 0../src/session.cpp:539In C++17. use if constexpr instead
    relevance 0../src/create_torrent.cpp:609this can be optimized
    relevance 0../src/create_torrent.cpp:611this can be optimized
    relevance 0../src/add_torrent_params.cpp:78pre C++17, GCC and msvc does not make std::string nothrow move assignable, which means no type containing a string will be nothrow move assignable by default either static_assert(std::is_nothrow_move_assignable::value , "should be nothrow move assignable");
    relevance 0../src/add_torrent_params.cpp:78pre C++17, GCC and msvc does not make std::string nothrow move assignable, which means no type containing a string will be nothrow move assignable by default either static_assert(std::is_nothrow_move_assignable::value , "should be nothrow move assignable");
    relevance 0../src/add_torrent_params.cpp:84it would be nice if this was nothrow default constructible static_assert(std::is_nothrow_default_constructible::value , "should be nothrow default constructible");
    relevance 0../src/add_torrent_params.cpp:84it would be nice if this was nothrow default constructible static_assert(std::is_nothrow_default_constructible::value , "should be nothrow default constructible");
    relevance 0../src/torrent_peer.cpp:179how do we deal with our external address changing?
    relevance 0../src/torrent_peer.cpp:179how do we deal with our external address changing?
    relevance 0../src/alert.cpp:403move this field into tracker_alert
    relevance 0../src/alert.cpp:404move this field into tracker_alert
    relevance 0../src/alert.cpp:437move this into tracker_alert
    relevance 0../src/alert.cpp:438move this into tracker_alert
    relevance 0../src/alert.cpp:463move this into tracker_alert
    relevance 0../src/alert.cpp:464move this into tracker_alert
    relevance 0../src/alert.cpp:492move this into tracker_alert
    relevance 0../src/alert.cpp:493move this into tracker_alert
    relevance 0../src/alert.cpp:531move this field into tracker_alert
    relevance 0../src/alert.cpp:532move this field into tracker_alert
    relevance 0../src/alert.cpp:575move this to tracker_alert
    relevance 0../src/alert.cpp:576move this to tracker_alert
    relevance 0../src/udp_tracker_connection.cpp:633why is this a linked list?
    relevance 0../src/udp_tracker_connection.cpp:633why is this a linked list?
    relevance 0../src/session_handle.cpp:485in C++14, use unique_ptr and move it into the lambda
    relevance 0../src/session_handle.cpp:485in C++14, use unique_ptr and move it into the lambda
    relevance 0../src/http_seed_connection.cpp:425technically, this isn't supposed to happen, but it seems to sometimes. Some of the accounting is probably wrong in certain cases
    relevance 0../src/http_seed_connection.cpp:441technically, this isn't supposed to happen, but it seems to sometimes. Some of the accounting is probably wrong in certain cases
    relevance 0../src/utp_stream.cpp:1352this loop is not very efficient. It could be fixed by having a separate list of sequence numbers that need resending
    relevance 0../src/utp_stream.cpp:1467this loop is not very efficient. It could be fixed by having a separate list of sequence numbers that need resending
    relevance 0../src/disabled_disk_io.cpp:106it would be nice to return a valid hash of zeroes here
    relevance 0../src/disabled_disk_io.cpp:106it would be nice to return a valid hash of zeroes here
    relevance 0../src/magnet_uri.cpp:434what's the right number here?
    relevance 0../src/magnet_uri.cpp:439what's the right number here?
    relevance 0../src/choker.cpp:255make configurable
    relevance 0../src/choker.cpp:255make configurable
    relevance 0../src/posix_part_file.cpp:337what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal
    relevance 0../src/posix_part_file.cpp:337what do we do if someone is currently reading from the disk from this piece? does it matter? Since we won't actively erase the data from disk, but it may be overwritten soon, it's probably not that big of a deal
    relevance 0../src/posix_part_file.cpp:425instead of rebuilding the whole file header and flushing it, update the slot entries as we go
    relevance 0../src/posix_part_file.cpp:425instead of rebuilding the whole file header and flushing it, update the slot entries as we go
    relevance 0../src/udp_socket.cpp:659perhaps an attempt should be made to bind m_socks5_sock to the device of m_listen_socket
    relevance 0../src/udp_socket.cpp:659perhaps an attempt should be made to bind m_socks5_sock to the device of m_listen_socket
    relevance 0../src/cpuid.cpp:131enable when aarch64 is really tested
    relevance 0../src/cpuid.cpp:131enable when aarch64 is really tested
    relevance 0../src/storage_utils.cpp:223ideally, if we end up copying files because of a move across volumes, the source should not be deleted until they've all been copied. That would let us rollback with higher confidence.
    relevance 0../src/storage_utils.cpp:223ideally, if we end up copying files because of a move across volumes, the source should not be deleted until they've all been copied. That would let us rollback with higher confidence.
    relevance 0../src/storage_utils.cpp:531it would seem reasonable to, instead, set the have_pieces bits for the pieces representing these files, and resume with the normal logic
    relevance 0../src/storage_utils.cpp:531it would seem reasonable to, instead, set the have_pieces bits for the pieces representing these files, and resume with the normal logic
    relevance 0../src/torrent_handle.cpp:556support moving files into this call
    relevance 0../src/torrent_handle.cpp:589support moving files into this call
    relevance 0../src/piece_picker.cpp:121find a better place for this
    relevance 0../src/piece_picker.cpp:121find a better place for this
    relevance 0../src/piece_picker.cpp:2074this could probably be optimized by incrementally calling partial_sort to sort one more element in the list. Because chances are that we'll just need a single piece, and once we've picked from it we're done. Sorting the rest of the list in that case is a waste of time.
    relevance 0../src/piece_picker.cpp:2074this could probably be optimized by incrementally calling partial_sort to sort one more element in the list. Because chances are that we'll just need a single piece, and once we've picked from it we're done. Sorting the rest of the list in that case is a waste of time.
    relevance 0../src/piece_picker.cpp:2218Is it a good idea that this affinity takes precedence over piece priority?
    relevance 0../src/piece_picker.cpp:2218Is it a good idea that this affinity takes precedence over piece priority?
    relevance 0../src/piece_picker.cpp:2572when expanding pieces for cache stripe reasons, the !downloading condition doesn't make much sense
    relevance 0../src/piece_picker.cpp:2572when expanding pieces for cache stripe reasons, the !downloading condition doesn't make much sense
    relevance 0../src/piece_picker.cpp:3150should 5 be configurable?
    relevance 0../src/piece_picker.cpp:3150should 5 be configurable?
    relevance 0../src/session_impl.cpp:611come up with some abstraction to do this for gnutls as well load certificates from the windows system certificate store
    relevance 0../src/session_impl.cpp:614come up with some abstraction to do this for gnutls as well load certificates from the windows system certificate store
    relevance 0../src/session_impl.cpp:1476it would be nice to reserve() these vectors up front
    relevance 0../src/session_impl.cpp:1479it would be nice to reserve() these vectors up front
    relevance 0../src/session_impl.cpp:1957could this function be merged with expand_unspecified_addresses? right now both listen_endpoint_t and listen_interface_t are almost identical, maybe the latter could be removed too
    relevance 0../src/session_impl.cpp:1993could this function be merged with expand_unspecified_addresses? right now both listen_endpoint_t and listen_interface_t are almost identical, maybe the latter could be removed too
    relevance 0../src/session_impl.cpp:2265it would probably be better to do this by having a listen-socket "version" number that gets bumped. And instead of setting a bool to disable a tracker, we set the version number that it was disabled at. This change would affect the ABI in 1.2, so should be done in 2.0 or later
    relevance 0../src/session_impl.cpp:2301it would probably be better to do this by having a listen-socket "version" number that gets bumped. And instead of setting a bool to disable a tracker, we set the version number that it was disabled at. This change would affect the ABI in 1.2, so should be done in 2.0 or later
    relevance 0../src/session_impl.cpp:2822this size need to be capped
    relevance 0../src/session_impl.cpp:2861this size need to be capped
    relevance 0../src/session_impl.cpp:2847this size need to be capped
    relevance 0../src/session_impl.cpp:2886this size need to be capped
    relevance 0../src/session_impl.cpp:3539have a separate list for these connections, instead of having to loop through all of them
    relevance 0../src/session_impl.cpp:3578have a separate list for these connections, instead of having to loop through all of them
    relevance 0../src/session_impl.cpp:3572this should apply to all bandwidth channels
    relevance 0../src/session_impl.cpp:3611this should apply to all bandwidth channels
    relevance 0../src/session_impl.cpp:4263use a lower limit than m_settings.connections_limit to allocate the to 10% or so of connection slots for incoming connections cap this at max - 1, since we may add one below
    relevance 0../src/session_impl.cpp:4302use a lower limit than m_settings.connections_limit to allocate the to 10% or so of connection slots for incoming connections cap this at max - 1, since we may add one below
    relevance 0../src/session_impl.cpp:4408post a message to have this happen immediately instead of waiting for the next tick
    relevance 0../src/session_impl.cpp:4447post a message to have this happen immediately instead of waiting for the next tick
    relevance 0../src/session_impl.cpp:4735it might be a nice feature here to limit the number of torrents to send in a single update. By just posting the first n torrents, they would nicely be round-robined because the torrent lists are always pushed back. Perhaps the status_update_alert could even have a fixed array of n entries rather than a vector, to further improve memory locality.
    relevance 0../src/session_impl.cpp:4774it might be a nice feature here to limit the number of torrents to send in a single update. By just posting the first n torrents, they would nicely be round-robined because the torrent lists are always pushed back. Perhaps the status_update_alert could even have a fixed array of n entries rather than a vector, to further improve memory locality.
    relevance 0../src/session_impl.cpp:5110factor out this logic into a separate function for unit testing
    relevance 0../src/session_impl.cpp:5149factor out this logic into a separate function for unit testing
    relevance 0../src/session_impl.cpp:5830refactor, move the storage to dht_tracker
    relevance 0../src/session_impl.cpp:5865refactor, move the storage to dht_tracker
    relevance 0../src/session_impl.cpp:6216asserts that no outstanding async operations are still in flight
    relevance 0../src/session_impl.cpp:6252asserts that no outstanding async operations are still in flight
    relevance 0../src/load_torrent.cpp:103move the loading logic from torrent_info constructor into here
    relevance 0../src/load_torrent.cpp:121move the loading logic from torrent_info constructor into here
    relevance 0../src/kademlia/node.cpp:1173keep the returned value to pass as a limit to write_nodes_entries when implemented
    relevance 0../src/kademlia/node.cpp:1177keep the returned value to pass as a limit to write_nodes_entries when implemented
    relevance 0../src/kademlia/node.cpp:1201limit number of entries in the result
    relevance 0../src/kademlia/node.cpp:1205limit number of entries in the result
    relevance 0../src/kademlia/item.cpp:143implement ctor for entry from bdecode_node?
    relevance 0../src/kademlia/item.cpp:143implement ctor for entry from bdecode_node?
    relevance 0../src/kademlia/dht_tracker.cpp:317pick the closest node rather than the first
    relevance 0../src/kademlia/dht_tracker.cpp:317pick the closest node rather than the first
    relevance 0../src/kademlia/put_data.cpp:92what if o is not an instance of put_data_observer? This need to be redesigned for better type safety.
    relevance 0../src/kademlia/put_data.cpp:92what if o is not an instance of put_data_observer? This need to be redesigned for better type safety.
    relevance 0../src/kademlia/routing_table.cpp:289This is temporary. For now, only report the largest routing table (of potentially multiple ones, for multi-homed systems) in next major version, break the ABI and support reporting all of them in the dht_stats_alert
    relevance 0../src/kademlia/routing_table.cpp:289This is temporary. For now, only report the largest routing table (of potentially multiple ones, for multi-homed systems) in next major version, break the ABI and support reporting all of them in the dht_stats_alert
    relevance 0../src/kademlia/routing_table.cpp:314arvidn note when it's across IPv4 and IPv6, adding (dht_global_nodes) would make sense. in the future though, where we may have one DHT node per external interface (which may be multiple of the same address family), then it becomes a bit trickier
    relevance 0../src/kademlia/routing_table.cpp:314arvidn note when it's across IPv4 and IPv6, adding (dht_global_nodes) would make sense. in the future though, where we may have one DHT node per external interface (which may be multiple of the same address family), then it becomes a bit trickier
    relevance 0../src/kademlia/routing_table.cpp:518this need to take bucket "prefix" into account. It should be unified with add_node_impl()
    relevance 0../src/kademlia/routing_table.cpp:518this need to take bucket "prefix" into account. It should be unified with add_node_impl()
    relevance 0../src/kademlia/node_id.cpp:66it's a little bit weird to return 159 - leading zeroes. It should probably be 160 - leading zeroes, but all other code in here is tuned to this expectation now, and it doesn't really matter (other than complexity)
    relevance 0../src/kademlia/node_id.cpp:66it's a little bit weird to return 159 - leading zeroes. It should probably be 160 - leading zeroes, but all other code in here is tuned to this expectation now, and it doesn't really matter (other than complexity)
    relevance 0../include/libtorrent/piece_picker.hpp:802should this be allocated lazily?
    relevance 0../include/libtorrent/piece_picker.hpp:802should this be allocated lazily?
    relevance 0../include/libtorrent/piece_picker.hpp:877it would be more intuitive to account "wanted" pieces instead of filtered
    relevance 0../include/libtorrent/piece_picker.hpp:877it would be more intuitive to account "wanted" pieces instead of filtered
    relevance 0../include/libtorrent/torrent.hpp:271make this a raw pointer. perhaps keep the shared_ptr around further down the object to maintain an owner
    relevance 0../include/libtorrent/torrent.hpp:280make this a raw pointer. perhaps keep the shared_ptr around further down the object to maintain an owner
    relevance 0../include/libtorrent/torrent.hpp:452make graceful pause also finish all sending blocks before disconnecting
    relevance 0../include/libtorrent/torrent.hpp:463make graceful pause also finish all sending blocks before disconnecting
    relevance 0../include/libtorrent/torrent.hpp:1367this wastes 5 bits per file
    relevance 0../include/libtorrent/torrent.hpp:600make this flag a combination of the other ones
    relevance 0../include/libtorrent/torrent.hpp:1396this wastes 5 bits per file
    relevance 0../include/libtorrent/torrent.hpp:1684this member can probably be removed
    relevance 0../include/libtorrent/torrent.hpp:1711this member can probably be removed
    relevance 0../include/libtorrent/announce_entry.hpp:76include the number of peers received from this tracker, at last announce
    relevance 0../include/libtorrent/proxy_base.hpp:207it would be nice to remember the bind port and bind once we know where the proxy is m_sock.bind(endpoint, ec);
    relevance 0../include/libtorrent/i2p_stream.hpp:538make this a string_view
    relevance 0../include/libtorrent/proxy_base.hpp:207it would be nice to remember the bind port and bind once we know where the proxy is m_sock.bind(endpoint, ec);
    relevance 0../include/libtorrent/socket_type.hpp:60move to aux
    relevance 0../include/libtorrent/socket_type.hpp:60move to aux
    relevance 0../include/libtorrent/upnp.hpp:162support using the windows API for UPnP operations as well
    relevance 0../include/libtorrent/upnp.hpp:162support using the windows API for UPnP operations as well
    relevance 0../include/libtorrent/hash_picker.hpp:143support batched adding of block hashes for reduced overhead?
    relevance 0../include/libtorrent/hash_picker.hpp:155support batched adding of block hashes for reduced overhead?
    relevance 0../include/libtorrent/string_view.hpp:40replace this by the standard string_view in C++17
    relevance 0../include/libtorrent/string_view.hpp:40replace this by the standard string_view in C++17
    relevance 0../include/libtorrent/peer_connection.hpp:218make this a raw pointer (to save size in the first cache line) and make the constructor take a raw pointer. torrent objects should always outlive their peers
    relevance 0../include/libtorrent/peer_connection.hpp:218make this a raw pointer (to save size in the first cache line) and make the constructor take a raw pointer. torrent objects should always outlive their peers
    relevance 0../include/libtorrent/peer_connection.hpp:1020factor this out into its own class with a virtual interface torrent and session should implement this interface
    relevance 0../include/libtorrent/peer_connection.hpp:1026factor this out into its own class with a virtual interface torrent and session should implement this interface
    relevance 0../include/libtorrent/identify_client.hpp:48hide this declaration when deprecated functions are disabled, and remove its internal use
    relevance 0../include/libtorrent/identify_client.hpp:48hide this declaration when deprecated functions are disabled, and remove its internal use
    relevance 0../include/libtorrent/socks5_stream.hpp:197we could bind the socket here, since we know what the target endpoint is of the proxy
    relevance 0../include/libtorrent/socks5_stream.hpp:197we could bind the socket here, since we know what the target endpoint is of the proxy
    relevance 0../include/libtorrent/torrent_info.hpp:715change the type to std::shared_ptr in C++17 it is used as if immutable, it cannot be const for technical reasons right now.
    relevance 0../include/libtorrent/torrent_info.hpp:729change the type to std::shared_ptr in C++17 it is used as if immutable, it cannot be const for technical reasons right now.
    relevance 0../include/libtorrent/performance_counters.hpp:485some space could be saved here by making gauges 32 bits
    relevance 0../include/libtorrent/performance_counters.hpp:486restore these to regular integers. Instead have one copy of the counters per thread and collect them at convenient synchronization points
    relevance 0../include/libtorrent/performance_counters.hpp:485some space could be saved here by making gauges 32 bits
    relevance 0../include/libtorrent/performance_counters.hpp:486restore these to regular integers. Instead have one copy of the counters per thread and collect them at convenient synchronization points
    relevance 0../include/libtorrent/kademlia/msg.hpp:87move this to its own .hpp/.cpp pair?
    relevance 0../include/libtorrent/kademlia/msg.hpp:87move this to its own .hpp/.cpp pair?
    relevance 0../include/libtorrent/kademlia/item.hpp:61since this is a public function, it should probably be moved out of this header and into one with other public functions.
    relevance 0../include/libtorrent/kademlia/item.hpp:61since this is a public function, it should probably be moved out of this header and into one with other public functions.
    relevance 0../include/libtorrent/aux_/deprecated.hpp:47figure out which version of clang this is supported in
    relevance 0../include/libtorrent/aux_/deprecated.hpp:47figure out which version of clang this is supported in
    relevance 0../include/libtorrent/aux_/session_interface.hpp:212it would be nice to not have this be part of session_interface
    relevance 0../include/libtorrent/aux_/session_interface.hpp:212it would be nice to not have this be part of session_interface
    relevance 0../include/libtorrent/aux_/announce_entry.hpp:74include the number of peers received from this tracker, at last announce
    relevance 0../include/libtorrent/aux_/announce_entry.hpp:74include the number of peers received from this tracker, at last announce
    relevance 0../include/libtorrent/aux_/session_impl.hpp:264make these direct members and generate shared_ptrs to them which alias the listen_socket_t shared_ptr
    relevance 0../include/libtorrent/aux_/session_impl.hpp:264make these direct members and generate shared_ptrs to them which alias the listen_socket_t shared_ptr
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1062replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1066replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1067replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1071replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1074replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/session_impl.hpp:1078replace this by a proper asio timer
    relevance 0../include/libtorrent/aux_/pool.hpp:49ensure the alignment is good here
    relevance 0../include/libtorrent/aux_/pool.hpp:49ensure the alignment is good here
    relevance 0../include/libtorrent/aux_/allocating_handler.hpp:312in C++17, Handler and Storage could just use "auto"
    relevance 0../include/libtorrent/aux_/allocating_handler.hpp:317in C++17, Handler and Storage could just use "auto"
    relevance 0../include/libtorrent/aux_/merkle_tree.hpp:85remove this constructor. Don't support "uninitialized" trees. This also requires not constructing these for pad-files and small files as well. So, a sparse hash list in torrent_info
    relevance 0../include/libtorrent/aux_/merkle_tree.hpp:85remove this constructor. Don't support "uninitialized" trees. This also requires not constructing these for pad-files and small files as well. So, a sparse hash list in torrent_info
    relevance 0../include/libtorrent/aux_/merkle_tree.hpp:175make this a std::unique_ptr
    relevance 0../include/libtorrent/aux_/merkle_tree.hpp:175make this a std::unique_ptr
    relevance 0../include/libtorrent/aux_/utp_stream.hpp:642it would be nice to make this private
    relevance 0../include/libtorrent/aux_/utp_stream.hpp:693it would be nice to make this private
    \ No newline at end of file diff --git a/3rd/libtorrent-rasterbar/docs/troubleshooting.html b/3rd/libtorrent-rasterbar/docs/troubleshooting.html index dea40d24..618cfdcb 100644 --- a/3rd/libtorrent-rasterbar/docs/troubleshooting.html +++ b/3rd/libtorrent-rasterbar/docs/troubleshooting.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,7 +25,7 @@

    libtorrent manual

    Version: -2.0.8 +2.0.9

    The following troubleshooting chart may help in finding out why torrents fail diff --git a/3rd/libtorrent-rasterbar/docs/tuning-ref.html b/3rd/libtorrent-rasterbar/docs/tuning-ref.html index 7f445077..be9cf59c 100644 --- a/3rd/libtorrent-rasterbar/docs/tuning-ref.html +++ b/3rd/libtorrent-rasterbar/docs/tuning-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,34 +25,34 @@ Version: -2.0.8 +2.0.9

    diff --git a/3rd/libtorrent-rasterbar/docs/tutorial-ref.html b/3rd/libtorrent-rasterbar/docs/tutorial-ref.html index f1647237..9faa61a7 100644 --- a/3rd/libtorrent-rasterbar/docs/tutorial-ref.html +++ b/3rd/libtorrent-rasterbar/docs/tutorial-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,23 +25,23 @@ Version: -2.0.8 +2.0.9

    Table of contents

      -
    • tutorial @@ -307,12 +307,12 @@

      example

      #pragma clang diagnostic ignored "-Wcovered-switch-default" #endif switch(s) { - case lt::torrent_status::checking_files: return "checking"; - case lt::torrent_status::downloading_metadata: return "dl metadata"; - case lt::torrent_status::downloading: return "downloading"; - case lt::torrent_status::finished: return "finished"; - case lt::torrent_status::seeding: return "seeding"; - case lt::torrent_status::checking_resume_data: return "checking resume"; + case lt::torrent_status::checking_files: return "checking"; + case lt::torrent_status::downloading_metadata: return "dl metadata"; + case lt::torrent_status::downloading: return "downloading"; + case lt::torrent_status::finished: return "finished"; + case lt::torrent_status::seeding: return "seeding"; + case lt::torrent_status::checking_resume_data: return "checking resume"; default: return "<>"; } #ifdef __clang__ @@ -339,7 +339,7 @@

      example

      clk::time_point last_save_resume = clk::now(); // load resume data from disk and pass it in as we add the magnet link - std::ifstream ifs(".resume_file", std::ios_base::binary); + std::ifstream ifs(".resume_file", std::ios_base::binary); ifs.unsetf(std::ios_base::skipws); std::vector<char> buf{std::istream_iterator<char>(ifs) , std::istream_iterator<char>()}; @@ -381,7 +381,7 @@

      example

      // when resume data is ready, save it if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) { - std::ofstream of(".resume_file", std::ios_base::binary); + std::ofstream of(".resume_file", std::ios_base::binary); of.unsetf(std::ios_base::skipws); auto const b = write_resume_data_buf(rd->params); of.write(b.data(), int(b.size())); @@ -448,7 +448,7 @@

      session state

      update the settings_pack (params) member of settings_params, or configuring the disk_io_constructor.

    -
    +

    example

    Another updated version of the above example with the following updates:

      @@ -486,12 +486,12 @@

      example

      #pragma clang diagnostic ignored "-Wcovered-switch-default" #endif switch(s) { - case lt::torrent_status::checking_files: return "checking"; - case lt::torrent_status::downloading_metadata: return "dl metadata"; - case lt::torrent_status::downloading: return "downloading"; - case lt::torrent_status::finished: return "finished"; - case lt::torrent_status::seeding: return "seeding"; - case lt::torrent_status::checking_resume_data: return "checking resume"; + case lt::torrent_status::checking_files: return "checking"; + case lt::torrent_status::downloading_metadata: return "dl metadata"; + case lt::torrent_status::downloading: return "downloading"; + case lt::torrent_status::finished: return "finished"; + case lt::torrent_status::seeding: return "seeding"; + case lt::torrent_status::checking_resume_data: return "checking resume"; default: return "<>"; } #ifdef __clang__ @@ -584,7 +584,7 @@

      example

      // when resume data is ready, save it if (auto rd = lt::alert_cast<lt::save_resume_data_alert>(a)) { - std::ofstream of(".resume_file", std::ios_base::binary); + std::ofstream of(".resume_file", std::ios_base::binary); of.unsetf(std::ios_base::skipws); auto const b = write_resume_data_buf(rd->params); of.write(b.data(), int(b.size())); @@ -626,7 +626,7 @@

      example

      done: std::cout << "\nsaving session state" << std::endl; { - std::ofstream of(".session", std::ios_base::binary); + std::ofstream of(".session", std::ios_base::binary); of.unsetf(std::ios_base::skipws); auto const b = write_session_params_buf(ses.session_state() , lt::save_state_flags_t::all()); diff --git a/3rd/libtorrent-rasterbar/docs/udp_tracker_protocol.html b/3rd/libtorrent-rasterbar/docs/udp_tracker_protocol.html index 166eb2d6..4153e489 100644 --- a/3rd/libtorrent-rasterbar/docs/udp_tracker_protocol.html +++ b/3rd/libtorrent-rasterbar/docs/udp_tracker_protocol.html @@ -4,7 +4,7 @@ - + libtorrent @@ -32,18 +32,18 @@

      Bittorrent UDP-tracker protocol extension

      diff --git a/3rd/libtorrent-rasterbar/docs/upgrade_to_1.2-ref.html b/3rd/libtorrent-rasterbar/docs/upgrade_to_1.2-ref.html index 76264f80..54a79612 100644 --- a/3rd/libtorrent-rasterbar/docs/upgrade_to_1.2-ref.html +++ b/3rd/libtorrent-rasterbar/docs/upgrade_to_1.2-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -32,21 +32,21 @@

      Upgrading to libtorrent 1.2

      libtorrent version 1.2 comes with some significant updates in the API. diff --git a/3rd/libtorrent-rasterbar/docs/upgrade_to_2.0-ref.html b/3rd/libtorrent-rasterbar/docs/upgrade_to_2.0-ref.html index a8157cb2..4368569e 100644 --- a/3rd/libtorrent-rasterbar/docs/upgrade_to_2.0-ref.html +++ b/3rd/libtorrent-rasterbar/docs/upgrade_to_2.0-ref.html @@ -4,7 +4,7 @@ - + libtorrent @@ -32,35 +32,35 @@

      Upgrading to libtorrent 2.0

      In libtorrent 2.0, some parts of the API has changed and some deprecated parts diff --git a/3rd/libtorrent-rasterbar/docs/utp.html b/3rd/libtorrent-rasterbar/docs/utp.html index 7d9096a0..16318221 100644 --- a/3rd/libtorrent-rasterbar/docs/utp.html +++ b/3rd/libtorrent-rasterbar/docs/utp.html @@ -4,7 +4,7 @@ - + libtorrent @@ -25,20 +25,20 @@ Version: -2.0.8 +2.0.9

      Table of contents

        -
      • uTP diff --git a/3rd/libtorrent-rasterbar/examples/client_test.cpp b/3rd/libtorrent-rasterbar/examples/client_test.cpp index 5d027ac6..59e68ef1 100644 --- a/3rd/libtorrent-rasterbar/examples/client_test.cpp +++ b/3rd/libtorrent-rasterbar/examples/client_test.cpp @@ -210,6 +210,7 @@ bool print_log = false; bool print_downloads = false; bool print_matrix = false; bool print_file_progress = false; +bool print_piece_availability = false; bool show_pad_files = false; bool show_dht_status = false; @@ -329,6 +330,56 @@ int peer_index(lt::tcp::endpoint addr, std::vector const& peers) return int(i - peers.begin()); } +#if TORRENT_USE_I2P +void base32encode_i2p(lt::sha256_hash const& s, std::string& out, int limit) +{ + static char const base32_table[] = + { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '2', '3', '4', '5', '6', '7' + }; + + static std::array const input_output_mapping{{0, 2, 4, 5, 7, 8}}; + + std::array inbuf; + std::array outbuf; + + TORRENT_ASSERT(s.size() % 5 ); + for (auto i = s.begin(); i != s.end();) + { + int const available_input = std::min(int(inbuf.size()), int(s.end() - i)); + + // clear input buffer + inbuf.fill(0); + + // read a chunk of input into inbuf + std::copy(i, i + available_input, inbuf.begin()); + i += available_input; + + // encode inbuf to outbuf + outbuf[0] = (inbuf[0] & 0xf8) >> 3; + outbuf[1] = (((inbuf[0] & 0x07) << 2) | ((inbuf[1] & 0xc0) >> 6)) & 0xff; + outbuf[2] = ((inbuf[1] & 0x3e) >> 1); + outbuf[3] = (((inbuf[1] & 0x01) << 4) | ((inbuf[2] & 0xf0) >> 4)) & 0xff; + outbuf[4] = (((inbuf[2] & 0x0f) << 1) | ((inbuf[3] & 0x80) >> 7)) & 0xff; + outbuf[5] = ((inbuf[3] & 0x7c) >> 2); + outbuf[6] = (((inbuf[3] & 0x03) << 3) | ((inbuf[4] & 0xe0) >> 5)) & 0xff; + outbuf[7] = inbuf[4] & 0x1f; + + // write output + int const num_out = input_output_mapping[std::size_t(available_input)]; + for (int j = 0; j < num_out; ++j) + { + out += base32_table[outbuf[std::size_t(j)]]; + --limit; + if (limit <= 0) return; + } + } +} +#endif + // returns the number of lines printed int print_peer_info(std::string& out , std::vector const& peers, int max_lines) @@ -362,13 +413,29 @@ int print_peer_info(std::string& out if (print_ip) { - std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->ip).c_str()); - out += str; +#if TORRENT_USE_I2P + if (i->flags & peer_info::i2p_socket) + { + base32encode_i2p(i->i2p_destination(), out, 31); + } + else +#endif + { + std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->ip).c_str()); + out += str; + } } if (print_local_ip) { - std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->local_endpoint).c_str()); - out += str; +#if TORRENT_USE_I2P + if (i->flags & peer_info::i2p_socket) + out += " "; + else +#endif + { + std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->local_endpoint).c_str()); + out += str; + } } char temp[10]; @@ -649,7 +716,6 @@ void assign_setting(lt::settings_pack& settings, std::string const& key, char co {"socks5_pw"_sv, settings_pack::socks5_pw}, {"http"_sv, settings_pack::http}, {"http_pw"_sv, settings_pack::http_pw}, - {"i2p_proxy"_sv, settings_pack::i2p_proxy}, }; { @@ -913,19 +979,79 @@ int save_file(std::string const& filename, std::vector const& v) return !f.fail(); } +struct client_state_t +{ + torrent_view& view; + session_view& ses_view; + std::deque events; + std::vector peers; + std::vector file_progress; + std::vector download_queue; + std::vector download_queue_block_info; + std::vector piece_availability; + std::vector trackers; + + void clear() + { + peers.clear(); + file_progress.clear(); + download_queue.clear(); + download_queue_block_info.clear(); + piece_availability.clear(); + trackers.clear(); + } +}; + // returns true if the alert was handled (and should not be printed to the log) // returns false if the alert was not handled -bool handle_alert(torrent_view& view, session_view& ses_view - , lt::session&, lt::alert* a) +bool handle_alert(client_state_t& client_state, lt::alert* a) { using namespace lt; if (session_stats_alert* s = alert_cast(a)) { - ses_view.update_counters(s->counters(), s->timestamp()); + client_state.ses_view.update_counters(s->counters(), s->timestamp()); return !stats_enabled; } + if (auto* p = alert_cast(a)) + { + if (client_state.view.get_active_torrent().handle == p->handle) + client_state.peers = std::move(p->peer_info); + return true; + } + + if (auto* p = alert_cast(a)) + { + if (client_state.view.get_active_torrent().handle == p->handle) + client_state.file_progress = std::move(p->files); + return true; + } + + if (auto* p = alert_cast(a)) + { + if (client_state.view.get_active_torrent().handle == p->handle) + { + client_state.download_queue = std::move(p->piece_info); + client_state.download_queue_block_info = std::move(p->block_data); + } + return true; + } + + if (auto* p = alert_cast(a)) + { + if (client_state.view.get_active_torrent().handle == p->handle) + client_state.piece_availability = std::move(p->piece_availability); + return true; + } + + if (auto* p = alert_cast(a)) + { + if (client_state.view.get_active_torrent().handle == p->handle) + client_state.trackers = std::move(p->trackers); + return true; + } + #ifndef TORRENT_DISABLE_DHT if (dht_stats_alert* p = alert_cast(a)) { @@ -1022,7 +1148,7 @@ bool handle_alert(torrent_view& view, session_view& ses_view { torrent_handle h = p->handle; - h.save_resume_data(torrent_handle::save_info_dict | torrent_handle::only_if_modified); + h.save_resume_data(torrent_handle::save_info_dict | torrent_handle::if_metadata_changed); ++num_outstanding_resume_data; // if we have a peer specified, connect to it @@ -1050,7 +1176,7 @@ bool handle_alert(torrent_view& view, session_view& ses_view // the alert handler for save_resume_data_alert // will save it to disk torrent_handle h = p->handle; - h.save_resume_data(torrent_handle::save_info_dict); + h.save_resume_data(torrent_handle::save_info_dict | torrent_handle::if_download_progress); ++num_outstanding_resume_data; if (exit_on_finish) quit = true; } @@ -1072,23 +1198,31 @@ bool handle_alert(torrent_view& view, session_view& ses_view if (torrent_paused_alert* p = alert_cast(a)) { - // write resume data for the finished torrent - // the alert handler for save_resume_data_alert - // will save it to disk - torrent_handle h = p->handle; - h.save_resume_data(torrent_handle::save_info_dict); - ++num_outstanding_resume_data; + if (!quit) + { + // write resume data for the finished torrent + // the alert handler for save_resume_data_alert + // will save it to disk + torrent_handle h = p->handle; + h.save_resume_data(torrent_handle::save_info_dict); + ++num_outstanding_resume_data; + } } if (state_update_alert* p = alert_cast(a)) { - view.update_torrents(std::move(p->status)); + lt::torrent_handle const prev = client_state.view.get_active_handle(); + client_state.view.update_torrents(std::move(p->status)); + + // when the active torrent changes, we need to clear the peers, trackers, files, etc. + if (client_state.view.get_active_handle() != prev) + client_state.clear(); return true; } if (torrent_removed_alert* p = alert_cast(a)) { - view.remove_torrent(std::move(p->handle)); + client_state.view.remove_torrent(std::move(p->handle)); } return false; @@ -1098,20 +1232,19 @@ bool handle_alert(torrent_view& view, session_view& ses_view } -void pop_alerts(torrent_view& view, session_view& ses_view - , lt::session& ses, std::deque& events) +void pop_alerts(client_state_t& client_state, lt::session& ses) { std::vector alerts; ses.pop_alerts(&alerts); for (auto a : alerts) { - if (::handle_alert(view, ses_view, ses, a)) continue; + if (::handle_alert(client_state, a)) continue; // if we didn't handle the alert, print it to the log std::string event_string; print_alert(a, event_string); - events.push_back(event_string); - if (events.size() >= 20) events.pop_front(); + client_state.events.push_back(event_string); + if (client_state.events.size() >= 20) client_state.events.pop_front(); } } @@ -1308,8 +1441,6 @@ int main(int argc, char* argv[]) std::vector in; if (load_file(".ses_state", in)) params = read_session_params(in, session_handle::save_dht_state); - - params.settings.set_bool(settings_pack::dht_privacy_lookups, true); #endif auto& settings = params.settings; @@ -1334,7 +1465,9 @@ int main(int argc, char* argv[]) lt::time_duration refresh_delay = lt::milliseconds(500); bool rate_limit_locals = false; - std::deque events; + client_state_t client_state{ + view, ses_view, {}, {}, {}, {}, {}, {}, {} + }; int loop_limit = -1; lt::time_point next_dir_scan = lt::clock_type::now(); @@ -1522,7 +1655,6 @@ int main(int argc, char* argv[]) }); // main loop - std::vector peers; #ifndef _WIN32 signal(SIGTERM, signal_handler); @@ -1601,6 +1733,7 @@ int main(int argc, char* argv[]) int const filter = view.filter(); if (filter > 0) { + client_state.clear(); view.set_filter(filter - 1); h = view.get_active_handle(); } @@ -1610,26 +1743,37 @@ int main(int argc, char* argv[]) int const filter = view.filter(); if (filter < torrent_view::torrents_max - 1) { + client_state.clear(); view.set_filter(filter + 1); h = view.get_active_handle(); } } else if (c2 == up_arrow) { + client_state.clear(); view.arrow_up(); h = view.get_active_handle(); } else if (c2 == down_arrow) { + client_state.clear(); view.arrow_down(); h = view.get_active_handle(); } } - if (c == ' ') + if (c == '<') { - if (ses.is_paused()) ses.resume(); - else ses.pause(); + int const order = view.sort_order(); + if (order > 0) + view.set_sort_order(order - 1); + } + + if (c == '>') + { + int const order = view.sort_order(); + if (order < 2) + view.set_sort_order(order + 1); } if (c == '[' && h.is_valid()) @@ -1702,6 +1846,7 @@ int main(int argc, char* argv[]) std::printf("failed to delete torrent, invalid handle: %s\n" , st.name.c_str()); } + client_state.clear(); } } @@ -1793,6 +1938,7 @@ int main(int argc, char* argv[]) if (c == 'd') print_downloads = !print_downloads; if (c == 'y') print_matrix = !print_matrix; if (c == 'f') print_file_progress = !print_file_progress; + if (c == 'a') print_piece_availability = !print_piece_availability; if (c == 'P') show_pad_files = !show_pad_files; if (c == 'g') show_dht_status = !show_dht_status; if (c == 'x') print_disk_stats = !print_disk_stats; @@ -1835,6 +1981,7 @@ up/down arrow keys: select torrent [g] show DHT [x] toggle disk cache stats [t] show trackers [l] toggle show log [y] toggle show piece matrix [I] toggle show peer flag legend +[a] toggle show piece availability COLUMN OPTIONS [1] toggle IP column [2] toggle show peer connection attempts @@ -1854,7 +2001,7 @@ COLUMN OPTIONS } } - pop_alerts(view, ses_view, ses, events); + pop_alerts(client_state, ses); std::string out; @@ -1934,8 +2081,9 @@ COLUMN OPTIONS if ((print_downloads && s.state != torrent_status::seeding) || print_peers) - h.get_peer_info(peers); + h.post_peer_info(); + auto& peers = client_state.peers; if (print_peers && !peers.empty()) { using lt::peer_info; @@ -1972,8 +2120,8 @@ COLUMN OPTIONS , s.current_tracker.c_str()); out += str; pos += 1; - std::vector tr = h.trackers(); - for (lt::announce_entry const& ae : h.trackers()) + h.post_trackers(); + for (lt::announce_entry const& ae : client_state.trackers) { std::snprintf(str, sizeof(str), "%2d %-55s %s\x1b[K\n" , ae.tier, ae.url.c_str(), ae.verified?"OK ":"- "); @@ -2020,12 +2168,19 @@ COLUMN OPTIONS pos += height_out; } + if (print_piece_availability) + { + h.post_piece_availability(); + if (!client_state.piece_availability.empty()) + print(avail_bar(client_state.piece_availability, terminal_width, pos).c_str()); + } + if (print_downloads) { - std::vector queue = h.get_download_queue(); + h.post_download_queue(); int p = 0; // this is horizontal position - for (lt::partial_piece_info const& i : queue) + for (lt::partial_piece_info const& i : client_state.download_queue) { if (pos + 3 >= terminal_height) break; @@ -2062,16 +2217,19 @@ COLUMN OPTIONS pos += 1; } - if (print_file_progress && s.has_metadata) + if (print_file_progress && s.has_metadata && h.is_valid()) { - std::vector const file_progress = h.file_progress(); + h.post_file_progress({}); std::vector file_status = h.file_status(); std::vector file_prio = h.get_file_priorities(); auto f = file_status.begin(); - std::shared_ptr ti = h.torrent_file(); + std::shared_ptr ti = s.torrent_file.lock(); + + // TODO: ti may be nullptr here, we should check + auto const& file_progress = client_state.file_progress; int p = 0; // this is horizontal position - for (file_index_t i(0); i < file_index_t(ti->num_files()); ++i) + for (file_index_t const i : ti->files().file_range()) { auto const idx = std::size_t(static_cast(i)); if (pos + 1 >= terminal_height) break; @@ -2079,9 +2237,11 @@ COLUMN OPTIONS bool const pad_file = ti->files().pad_file_at(i); if (pad_file && !show_pad_files) continue; + if (idx >= file_progress.size()) break; + int const progress = ti->files().file_size(i) > 0 ? int(file_progress[idx] * 1000 / ti->files().file_size(i)) : 1000; - assert(file_progress[idx] <= ti->files().file_size(i)); + TORRENT_ASSERT(file_progress[idx] <= ti->files().file_size(i)); bool const complete = file_progress[idx] == ti->files().file_size(i); @@ -2137,7 +2297,7 @@ COLUMN OPTIONS if (print_log) { - for (auto const& e : events) + for (auto const& e : client_state.events) { if (pos + 1 >= terminal_height) break; out += e; @@ -2161,6 +2321,7 @@ COLUMN OPTIONS resume_data_loader.join(); + quit = true; ses.pause(); std::printf("saving resume data\n"); @@ -2181,7 +2342,7 @@ COLUMN OPTIONS if ((idx % 32) == 0) { std::printf("\r%d ", num_outstanding_resume_data); - pop_alerts(view, ses_view, ses, events); + pop_alerts(client_state, ses); } } std::printf("\nwaiting for resume data [%d]\n", num_outstanding_resume_data); @@ -2190,7 +2351,7 @@ COLUMN OPTIONS { alert const* a = ses.wait_for_alert(seconds(10)); if (a == nullptr) continue; - pop_alerts(view, ses_view, ses, events); + pop_alerts(client_state, ses); } if (g_log_file) std::fclose(g_log_file); diff --git a/3rd/libtorrent-rasterbar/examples/connection_tester.cpp b/3rd/libtorrent-rasterbar/examples/connection_tester.cpp index ae9119a2..2dfa278d 100644 --- a/3rd/libtorrent-rasterbar/examples/connection_tester.cpp +++ b/3rd/libtorrent-rasterbar/examples/connection_tester.cpp @@ -1091,9 +1091,9 @@ int main(int argc, char* argv[]) // 1 MiB piece size const int piece_size = 1024 * 1024; lt::create_torrent t(fs, piece_size, lt::create_torrent::v1_only); - sha1_hash zero(nullptr); - for (auto const k : fs.piece_range()) - t.set_hash(k, zero); + sha1_hash dummy("abcdefghijklmnopqrst"); + for (auto const k : t.piece_range()) + t.set_hash(k, dummy); int tier = 0; for (auto const& tr : trackers) diff --git a/3rd/libtorrent-rasterbar/examples/dump_torrent.cpp b/3rd/libtorrent-rasterbar/examples/dump_torrent.cpp index 1077ef22..664e13b0 100644 --- a/3rd/libtorrent-rasterbar/examples/dump_torrent.cpp +++ b/3rd/libtorrent-rasterbar/examples/dump_torrent.cpp @@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/bencode.hpp" -#include "libtorrent/torrent_info.hpp" +#include "libtorrent/load_torrent.hpp" #include "libtorrent/bdecode.hpp" #include "libtorrent/magnet_uri.hpp" #include "libtorrent/span.hpp" @@ -114,27 +114,36 @@ int main(int argc, char const* argv[]) try } } - lt::torrent_info const t(filename, cfg); + lt::add_torrent_params const atp = lt::load_torrent_file(filename, cfg); // print info about torrent - if (!t.nodes().empty()) + if (!atp.dht_nodes.empty()) { std::printf("nodes:\n"); - for (auto const& i : t.nodes()) + for (auto const& i : atp.dht_nodes) std::printf("%s: %d\n", i.first.c_str(), i.second); } - if (!t.trackers().empty()) + if (!atp.trackers.empty()) { puts("trackers:\n"); - for (auto const& i : t.trackers()) - std::printf("%2d: %s\n", i.tier, i.url.c_str()); + auto tier_it = atp.tracker_tiers.begin(); + int tier = 0; + for (auto const& i : atp.trackers) + { + if (tier_it != atp.tracker_tiers.end()) + { + tier = *tier_it; + ++tier_it; + } + std::printf("%2d: %s\n", tier, i.c_str()); + } } std::stringstream ih; - ih << t.info_hashes().v1; - if (t.info_hashes().has_v2()) - ih << ", " << t.info_hashes().v2; + ih << atp.info_hashes.v1; + if (atp.info_hashes.has_v2()) + ih << ", " << atp.info_hashes.v2; std::printf("number of pieces: %d\n" "piece length: %d\n" "info hash: %s\n" @@ -144,15 +153,15 @@ int main(int argc, char const* argv[]) try "name: %s\n" "number of files: %d\n" "files:\n" - , t.num_pieces() - , t.piece_length() + , atp.ti->num_pieces() + , atp.ti->piece_length() , ih.str().c_str() - , t.comment().c_str() - , t.creator().c_str() - , make_magnet_uri(t).c_str() - , t.name().c_str() - , t.num_files()); - lt::file_storage const& st = t.files(); + , atp.ti->comment().c_str() + , atp.ti->creator().c_str() + , make_magnet_uri(atp).c_str() + , atp.name.c_str() + , atp.ti->num_files()); + lt::file_storage const& st = atp.ti->files(); for (auto const i : st.file_range()) { auto const first = st.map_file(i, 0, 0).piece; @@ -178,12 +187,8 @@ int main(int argc, char const* argv[]) try , (flags & lt::file_storage::flag_symlink) ? st.symlink(i).c_str() : ""); } std::printf("web seeds:\n"); - for (auto const& ws : t.web_seeds()) - { - std::printf("%s %s\n" - , ws.type == lt::web_seed_entry::url_seed ? "BEP19" : "BEP17" - , ws.url.c_str()); - } + for (auto const& ws : atp.url_seeds) + std::printf("%s\n", ws.c_str()); return 0; } diff --git a/3rd/libtorrent-rasterbar/examples/print.cpp b/3rd/libtorrent-rasterbar/examples/print.cpp index 120d34b1..2e18a75d 100644 --- a/3rd/libtorrent-rasterbar/examples/print.cpp +++ b/3rd/libtorrent-rasterbar/examples/print.cpp @@ -128,14 +128,6 @@ std::string const& progress_bar(int progress, int width, color_code c return bar; } -namespace { -int get_piece(lt::bitfield const& p, int index) -{ - if (index < 0 || index >= p.size()) return 0; - return p.get_bit(index) ? 1 : 0; -} -} - std::string const& piece_bar(lt::bitfield const& p, int width) { #ifdef _WIN32 @@ -208,6 +200,63 @@ std::string const& piece_bar(lt::bitfield const& p, int width) return bar; } +std::string avail_bar(lt::span avail, int const width, int& pos) +{ + std::string ret; + int const max_avail = (std::max)(1, *std::max_element(avail.begin(), avail.end())); + int cursor = 0; +#ifndef _WIN32 + for (int piece = 0; piece < avail.size(); piece += 2) + { + int p[2]; + p[0] = avail[piece] * 22 / max_avail; + p[1] = piece + 1 < avail.size() ? avail[piece + 1] * 22 / max_avail : 0; + assert(p[0] >= 0); + assert(p[0] < 23); + assert(p[1] >= 0); + assert(p[1] < 23); + char buf[50]; + std::snprintf(buf, sizeof(buf), "\x1b[38;5;%dm\x1b[48;5;%dm\u258c" + , 232 + p[0], 232 + p[1]); + ret += buf; + cursor += 1; + if (cursor >= width) + { + cursor = 0; + pos += 1; + ret += "\n"; + } + } +#else + for (int piece = 0; piece < avail.size(); ++piece) + { + static char const table[] = {' ', '\xb0', '\xb1', '\xb2', '\xdb'}; + int const p = avail[piece] * 4 / max_avail; + assert(p >= 0); + assert(p < 5); + ret += table[p]; + cursor += 1; + if (cursor >= width) + { + cursor = 0; + pos += 1; + ret += "\n"; + } + } +#endif + if (cursor > 0) + ret += "\x1b[K\n"; + return ret; +} + +namespace { +int get_piece(lt::bitfield const& p, int index) +{ + if (index < 0 || index >= p.size()) return 0; + return p.get_bit(index) ? 1 : 0; +} +} + #ifndef _WIN32 // this function uses the block characters that splits up the glyph in 4 // segments and provide all combinations of a segment lit or not. This allows us diff --git a/3rd/libtorrent-rasterbar/examples/print.hpp b/3rd/libtorrent-rasterbar/examples/print.hpp index f8a0430b..70348c8a 100644 --- a/3rd/libtorrent-rasterbar/examples/print.hpp +++ b/3rd/libtorrent-rasterbar/examples/print.hpp @@ -5,6 +5,7 @@ #include // for snprintf #include // for PRId64 et.al. #include "libtorrent/bitfield.hpp" +#include "libtorrent/span.hpp" enum color_code { @@ -38,6 +39,8 @@ std::string const& progress_bar(int progress, int width, color_code c = col_gree std::string const& piece_bar(lt::bitfield const& p, int width); +std::string avail_bar(lt::span avail, int const width, int& pos); + void set_cursor_pos(int x, int y); void clear_screen(); diff --git a/3rd/libtorrent-rasterbar/examples/session_view.cpp b/3rd/libtorrent-rasterbar/examples/session_view.cpp index 1c4c7d2f..cd8804ff 100644 --- a/3rd/libtorrent-rasterbar/examples/session_view.cpp +++ b/3rd/libtorrent-rasterbar/examples/session_view.cpp @@ -79,7 +79,6 @@ std::int64_t session_view::prev_value(int idx) const void session_view::render() { char str[1024]; - int pos = 0; int y = m_position; @@ -91,7 +90,7 @@ void session_view::render() int const upload_rate = int((value(m_sent_idx) - prev_value(m_sent_idx)) / seconds); - pos += std::snprintf(str, sizeof(str), "%s%s fail: %s down: %s (%s) " + std::snprintf(str, sizeof(str), "%s%s fail: %s down: %s (%s) " " bw queue: %s | %s conns: %3d unchoked: %2d / %2d queued-trackers: %02d%*s\x1b[K" , esc("48;5;238") , esc("1") diff --git a/3rd/libtorrent-rasterbar/examples/torrent_view.cpp b/3rd/libtorrent-rasterbar/examples/torrent_view.cpp index 098189df..68ee1689 100644 --- a/3rd/libtorrent-rasterbar/examples/torrent_view.cpp +++ b/3rd/libtorrent-rasterbar/examples/torrent_view.cpp @@ -75,13 +75,23 @@ std::string torrent_state(lt::torrent_status const& s) else ret += " [F]"; } - char buf[10]; - std::snprintf(buf, sizeof(buf), " (%.1f%%)", s.progress_ppm / 10000.0); - ret += buf; + if (s.flags & lt::torrent_flags::i2p_torrent) + ret += " i2p"; + if (s.state == lt::torrent_status::seeding) + { + ret += " "; + ret += add_suffix(s.total_done); + } + else + { + char buf[20]; + std::snprintf(buf, sizeof(buf), " (%.1f%%)", s.progress_ppm / 10000.0); + ret += buf; + } return ret; } -bool compare_torrent(lt::torrent_status const* lhs, lt::torrent_status const* rhs) +bool cmp_torrent_position(lt::torrent_status const* lhs, lt::torrent_status const* rhs) { if (lhs->queue_position != queue_position_t{-1} && rhs->queue_position != queue_position_t{-1}) { @@ -102,6 +112,16 @@ bool compare_torrent(lt::torrent_status const* lhs, lt::torrent_status const* rh < (rhs->queue_position == queue_position_t{-1}); } +bool cmp_torrent_name(lt::torrent_status const* lhs, lt::torrent_status const* rhs) +{ + return lhs->name < rhs->name; +} + +bool cmp_torrent_size(lt::torrent_status const* lhs, lt::torrent_status const* rhs) +{ + return lhs->total_done > rhs->total_done; +} + } torrent_view::torrent_view() = default; @@ -129,6 +149,20 @@ void torrent_view::set_filter(int filter) render(); } +int torrent_view::sort_order() const +{ + return m_sort_order; +} + +void torrent_view::set_sort_order(int const o) +{ + if (o == m_sort_order) return; + m_sort_order = order(o); + + update_sort_order(); + render(); +} + // returns the lt::torrent_status of the currently selected torrent. lt::torrent_status const& torrent_view::get_active_torrent() const { @@ -246,8 +280,9 @@ void torrent_view::arrow_up() if (m_active_torrent - 1 < m_scroll_position) { + int const scroll_step = std::max(m_height / 3, 8); --m_active_torrent; - m_scroll_position = m_active_torrent; + m_scroll_position = std::max(0, m_active_torrent - scroll_step); TORRENT_ASSERT(m_scroll_position >= 0); render(); return; @@ -265,13 +300,15 @@ void torrent_view::arrow_up() void torrent_view::arrow_down() { if (m_filtered_handles.empty()) return; - if (m_active_torrent >= int(m_filtered_handles.size()) - 1) return; + int const max_pos = int(m_filtered_handles.size()) - 1; + if (m_active_torrent >= max_pos) return; int bottom_pos = m_height - header_size - 1; if (m_active_torrent - m_scroll_position + 1 > bottom_pos) { + int const scroll_step = std::max(m_height / 3, 8); ++m_active_torrent; - m_scroll_position = m_active_torrent - bottom_pos; + m_scroll_position = std::min(max_pos, m_active_torrent + scroll_step) - bottom_pos; TORRENT_ASSERT(m_scroll_position >= 0); render(); return; @@ -348,20 +385,55 @@ void torrent_view::print_tabs() print(str.data()); } +namespace { + +struct column_info +{ + char const* name; + int width; + int sort_order; +}; + +std::array const torrent_columns = {{ + {"#", 3, 0}, + {"Name", 50, 1}, + {"Progress", 35, -1}, + {"Pieces", 14, 2}, + {"Download", 17, -1}, + {"Upload", 17, -1}, + {"Peers (D:S)", 11, -1}, + {"Down", 6, -1}, + {"Up", 6, -1}, + {"Flags", 4, -1}, +}}; + +} + void torrent_view::print_headers() { set_cursor_pos(0, 1); - std::array str; - // print title bar for torrent list - std::snprintf(str.data(), str.size() - , " %-3s %-50s %-35s %-14s %-17s %-17s %-11s %-6s %-6s %-4s\x1b[K" - , "#", "Name", "Progress", "Pieces", "Download", "Upload", "Peers (D:S)" - , "Down", "Up", "Flags"); + std::array str; + int cursor = 0; + for (auto const& ci : torrent_columns) + { + if (ci.sort_order == m_sort_order) + { + cursor += std::snprintf(str.data() + cursor, str.size() - std::size_t(cursor), "\x1b[7m"); + if (std::size_t(cursor) > str.size()) break; + } + cursor += std::snprintf(str.data() + cursor, str.size() - std::size_t(cursor), "%-*s ", ci.width, ci.name); + if (std::size_t(cursor) > str.size()) break; + if (ci.sort_order == m_sort_order) + { + cursor += std::snprintf(str.data() + cursor, str.size() - std::size_t(cursor), "\x1b[0m"); + if (std::size_t(cursor) > str.size()) break; + } + } + cursor += std::snprintf(str.data() + cursor, str.size() - std::size_t(cursor), "\x1b[K"); - if (m_width + 1 < int(str.size())) - str.back() = '\0'; + str.back() = '\0'; print(str.data()); } @@ -472,10 +544,27 @@ void torrent_view::update_filtered_torrents() if (m_active_torrent >= int(m_filtered_handles.size())) m_active_torrent = int(m_filtered_handles.size()) - 1; if (m_active_torrent < 0) m_active_torrent = 0; TORRENT_ASSERT(m_active_torrent >= 0); - std::sort(m_filtered_handles.begin(), m_filtered_handles.end(), &compare_torrent); + + update_sort_order(); if (m_scroll_position + m_height - header_size > int(m_filtered_handles.size())) { m_scroll_position = std::max(0, int(m_filtered_handles.size()) - m_height + header_size); } } + +void torrent_view::update_sort_order() +{ + switch (m_sort_order) + { + case order::queue: + std::sort(m_filtered_handles.begin(), m_filtered_handles.end(), &cmp_torrent_position); + break; + case order::name: + std::sort(m_filtered_handles.begin(), m_filtered_handles.end(), &cmp_torrent_name); + break; + case order::size: + std::sort(m_filtered_handles.begin(), m_filtered_handles.end(), &cmp_torrent_size); + break; + } +} diff --git a/3rd/libtorrent-rasterbar/examples/torrent_view.hpp b/3rd/libtorrent-rasterbar/examples/torrent_view.hpp index 55691470..12e1ba9d 100644 --- a/3rd/libtorrent-rasterbar/examples/torrent_view.hpp +++ b/3rd/libtorrent-rasterbar/examples/torrent_view.hpp @@ -48,6 +48,7 @@ struct torrent_view void set_size(int width, int height); + // torrent filter enum { torrents_all, torrents_downloading, @@ -60,10 +61,19 @@ struct torrent_view torrents_max }; - int filter() const; + // sort order + enum order: std::uint8_t { + queue, + name, + size, + }; + int filter() const; void set_filter(int filter); + int sort_order() const; + void set_sort_order(int); + // returns the lt::torrent_status of the currently selected torrent. lt::torrent_status const& get_active_torrent() const; lt::torrent_handle get_active_handle() const; @@ -95,6 +105,9 @@ struct torrent_view // visible or filtered void update_filtered_torrents(); + // re-sorts m_filtered_handles based on m_sort_order + void update_sort_order(); + // all torrents std::unordered_map m_all_handles; @@ -104,6 +117,7 @@ struct torrent_view mutable int m_active_torrent = 0; // index into m_filtered_handles int m_scroll_position = 0; int m_torrent_filter = 0; + order m_sort_order = order::queue; int m_width = 80; int m_height = 30; }; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/add_torrent_params.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/add_torrent_params.hpp index e73b9e16..db5ffb8b 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/add_torrent_params.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/add_torrent_params.hpp @@ -364,7 +364,9 @@ TORRENT_VERSION_NAMESPACE_3 aux::noexcept_movable> renamed_files; // the posix time of the last time payload was received or sent for this - // torrent, respectively. + // torrent, respectively. A value of 0 means we don't know when we last + // uploaded or downloaded, or we have never uploaded or downloaded any + // payload for this torrent. std::time_t last_download = 0; std::time_t last_upload = 0; @@ -404,7 +406,7 @@ TORRENT_VERSION_NAMESPACE_3 TORRENT_VERSION_NAMESPACE_3_END namespace aux { - bool contains_resume_data(add_torrent_params const&); + TORRENT_EXTRA_EXPORT bool contains_resume_data(add_torrent_params const&); } } diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/alert_types.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/alert_types.hpp index 98f8a050..a65d5624 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/alert_types.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/alert_types.hpp @@ -69,6 +69,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/tracker_manager.hpp" // for event_t #include "libtorrent/socket_type.hpp" #include "libtorrent/client_data.hpp" +#include "libtorrent/peer_info.hpp" // for peer_info #include "libtorrent/aux_/deprecated.hpp" #include "libtorrent/aux_/disable_warnings_push.hpp" @@ -98,7 +99,7 @@ namespace libtorrent { constexpr int user_alert_id = 10000; // this constant represents "max_alert_index" + 1 - constexpr int num_alert_types = 100; + constexpr int num_alert_types = 105; // internal constexpr int abi_alert_count = 128; @@ -3033,6 +3034,84 @@ TORRENT_VERSION_NAMESPACE_3_END std::shared_ptr metadata; }; + // posted when torrent_handle::post_peer_info() is called + struct TORRENT_EXPORT peer_info_alert final : torrent_alert + { + // internal + TORRENT_UNEXPORT peer_info_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector p); + TORRENT_DEFINE_ALERT_PRIO(peer_info_alert, 100, alert_priority::critical) + + static constexpr alert_category_t static_category = alert_category::status; + std::string message() const override; + + // the list of the currently connected peers + std::vector peer_info; + }; + + // posted when torrent_handle::post_file_progress() is called + struct TORRENT_EXPORT file_progress_alert final : torrent_alert + { + // internal + TORRENT_UNEXPORT file_progress_alert(aux::stack_allocator& alloc, torrent_handle h + , aux::vector fp); + TORRENT_DEFINE_ALERT_PRIO(file_progress_alert, 101, alert_priority::critical) + + static constexpr alert_category_t static_category = alert_category::file_progress; + std::string message() const override; + + // the list of the files in the torrent + aux::vector files; + }; + + // posted when torrent_handle::post_download_queue() is called + struct TORRENT_EXPORT piece_info_alert final : torrent_alert + { + // internal + TORRENT_UNEXPORT piece_info_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector pi, std::vector&& bd); + TORRENT_DEFINE_ALERT_PRIO(piece_info_alert, 102, alert_priority::critical) + + static constexpr alert_category_t static_category = alert_category::piece_progress; + std::string message() const override; + + // info about pieces being downloaded for the torrent + std::vector piece_info; + + // storage for block_info pointers in partial_piece_info objects + std::vector block_data; + }; + + // posted when torrent_handle::post_piece_availability() is called + struct TORRENT_EXPORT piece_availability_alert final : torrent_alert + { + // internal + TORRENT_UNEXPORT piece_availability_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector pa); + TORRENT_DEFINE_ALERT_PRIO(piece_availability_alert, 103, alert_priority::critical) + + static constexpr alert_category_t static_category = alert_category::status; + std::string message() const override; + + // info about pieces being downloaded for the torrent + std::vector piece_availability; + }; + + // posted when torrent_handle::post_trackers() is called + struct TORRENT_EXPORT tracker_list_alert final : torrent_alert + { + // internal + TORRENT_UNEXPORT tracker_list_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector t); + TORRENT_DEFINE_ALERT_PRIO(tracker_list_alert, 104, alert_priority::critical) + + static constexpr alert_category_t static_category = alert_category::status; + std::string message() const override; + + // list of trackers and their status for the torrent + std::vector trackers; + }; + // internal TORRENT_EXTRA_EXPORT char const* performance_warning_str(performance_alert::performance_warning_t i); diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/assert.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/assert.hpp index ef71df30..8e09de33 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/assert.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/assert.hpp @@ -85,6 +85,9 @@ extern TORRENT_EXPORT char const* libtorrent_assert_log; #ifndef TORRENT_USE_SYSTEM_ASSERTS +#define TORRENT_ASSERT_PRECOND_MSG(x, msg) \ + do { if (x) {} else libtorrent::assert_fail(#x, __LINE__, __FILE__, __func__, msg, 1); } TORRENT_WHILE_0 + #define TORRENT_ASSERT_PRECOND(x) \ do { if (x) {} else libtorrent::assert_fail(#x, __LINE__, __FILE__, __func__, nullptr, 1); } TORRENT_WHILE_0 @@ -110,6 +113,7 @@ extern TORRENT_EXPORT char const* libtorrent_assert_log; #else #include +#define TORRENT_ASSERT_PRECOND_MSG(x, msg) assert(x) #define TORRENT_ASSERT_PRECOND(x) assert(x) #define TORRENT_ASSERT(x) assert(x) #define TORRENT_ASSERT_VAL(x, y) assert(x) @@ -119,6 +123,7 @@ extern TORRENT_EXPORT char const* libtorrent_assert_log; #else // TORRENT_USE_ASSERTS +#define TORRENT_ASSERT_PRECOND_MSG(a, msg) do {} TORRENT_WHILE_0 #define TORRENT_ASSERT_PRECOND(a) do {} TORRENT_WHILE_0 #define TORRENT_ASSERT(a) do {} TORRENT_WHILE_0 #define TORRENT_ASSERT_VAL(a, b) do {} TORRENT_WHILE_0 diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/allocating_handler.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/allocating_handler.hpp index e23dad1e..9fcab19c 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/allocating_handler.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/allocating_handler.hpp @@ -70,8 +70,13 @@ namespace libtorrent { namespace aux { constexpr std::size_t debug_tick = 0; #endif #if TORRENT_USE_SSL +#ifdef __MINGW64__ + constexpr std::size_t openssl_read_cost = 26 + 21 * sizeof(void*); + constexpr std::size_t openssl_write_cost = 26 + 21 * sizeof(void*); +#else constexpr std::size_t openssl_read_cost = 26 + 14 * sizeof(void*); constexpr std::size_t openssl_write_cost = 26 + 14 * sizeof(void*); +#endif #else constexpr std::size_t openssl_read_cost = 0; constexpr std::size_t openssl_write_cost = 0; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/escape_string.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/escape_string.hpp index 1630c02d..0f039daf 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/escape_string.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/escape_string.hpp @@ -40,22 +40,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/error_code.hpp" #include "libtorrent/string_view.hpp" #include "libtorrent/flags.hpp" +#if TORRENT_USE_I2P +#include +#include "libtorrent/span.hpp" +#endif namespace libtorrent { - // hidden - using encode_string_flags_t = flags::bitfield_flag; - - namespace string - { - // use lower case alphabet used with i2p - constexpr encode_string_flags_t lowercase = 0_bit; - // don't insert padding - constexpr encode_string_flags_t no_padding = 1_bit; - // shortcut used for addresses as sha256 hashes - constexpr encode_string_flags_t i2p = lowercase | no_padding; - } - TORRENT_EXTRA_EXPORT std::string unescape_string(string_view s, error_code& ec); // replaces all disallowed URL characters by their %-encoding TORRENT_EXTRA_EXPORT std::string escape_string(string_view str); @@ -77,7 +68,8 @@ namespace libtorrent { TORRENT_EXTRA_EXPORT std::string base64encode(std::string const& s); #if TORRENT_USE_I2P // encodes a string using the base32 scheme - TORRENT_EXTRA_EXPORT std::string base32encode(string_view s, encode_string_flags_t flags = {}); + TORRENT_EXTRA_EXPORT std::string base32encode_i2p(span s); + TORRENT_EXTRA_EXPORT std::vector base64decode_i2p(string_view s); #endif TORRENT_EXTRA_EXPORT std::string base32decode(string_view s); diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/heterogeneous_queue.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/heterogeneous_queue.hpp index fe4550cc..b3bc9995 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/heterogeneous_queue.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/heterogeneous_queue.hpp @@ -43,6 +43,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/aux_/throw.hpp" +#ifdef TORRENT_ADDRESS_SANITIZER +#include +#endif + namespace libtorrent { namespace aux { @@ -82,6 +86,20 @@ namespace aux { static_assert(alignof(U) <= 256 , "heterogeneous_queue does not support types with alignment requirements > 256"); +#ifdef TORRENT_ADDRESS_SANITIZER + std::size_t const hdr_len = sizeof(U) + + aux::calculate_pad_bytes(ptr + sizeof(header_t) + pad_bytes + sizeof(U) + , alignof(header_t)); + + int const new_size = m_size + int(sizeof(header_t) + pad_bytes + hdr_len); + + __sanitizer_annotate_contiguous_container( + m_storage.get() + , m_storage.get() + m_capacity + , ptr + , m_storage.get() + new_size); +#endif + // if this assert triggers, the type being added to the queue has // alignment requirements stricter than what malloc() returns. This is // not supported @@ -99,7 +117,7 @@ namespace aux { hdr->move = &move; ptr += sizeof(header_t) + pad_bytes; hdr->len = static_cast(sizeof(U) - + aux::calculate_pad_bytes(ptr + sizeof(U), alignof(header_t))); + + aux::calculate_pad_bytes(ptr + sizeof(U), alignof(header_t))); // make sure ptr is correctly aligned for the object we're about to // create there @@ -113,6 +131,9 @@ namespace aux { // update counters to indicate the new item is in there ++m_num_items; m_size += int(sizeof(header_t) + pad_bytes + hdr->len); +#ifdef TORRENT_ADDRESS_SANITIZER + TORRENT_ASSERT(m_size == new_size); +#endif return *ret; } @@ -157,6 +178,17 @@ namespace aux { ptr += hdr->len; hdr->~header_t(); } + +#ifdef TORRENT_ADDRESS_SANITIZER + if (m_size > 0) + { + __sanitizer_annotate_contiguous_container( + m_storage.get() + , m_storage.get() + m_capacity + , m_storage.get() + m_size + , m_storage.get()); + } +#endif m_size = 0; m_num_items = 0; } @@ -224,12 +256,20 @@ namespace aux { // this is no-throw src_hdr->move(dst, src); src_hdr->~header_t(); - src += len ; + src += len; dst += len; } m_storage.swap(new_storage); m_capacity += amount_to_grow; + +#ifdef TORRENT_ADDRESS_SANITIZER + __sanitizer_annotate_contiguous_container( + m_storage.get() + , m_storage.get() + m_capacity + , m_storage.get() + , m_storage.get() + m_size); +#endif } template diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/numeric_cast.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/numeric_cast.hpp index cba398ab..0e6fcb35 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/numeric_cast.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/numeric_cast.hpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_NUMERIC_CAST_HPP #define TORRENT_NUMERIC_CAST_HPP +#include #include #include diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/packet_pool.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/packet_pool.hpp index 1786231c..f5a2ac66 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/packet_pool.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/packet_pool.hpp @@ -47,6 +47,10 @@ POSSIBILITY OF SUCH DAMAGE. #include // for unique_ptr #include +#ifdef TORRENT_ADDRESS_SANITIZER +#include +#endif + namespace libtorrent { namespace aux { @@ -67,6 +71,10 @@ namespace aux { // the last time this packet was sent time_point send_time; +#if TORRENT_USE_ASSERTS + int64_t num_fast_resend; +#endif + // the number of bytes actually allocated in 'buf' std::uint16_t allocated; @@ -90,20 +98,21 @@ namespace aux { // sent with the DF bit set (Don't Fragment) bool mtu_probe:1; -#if TORRENT_USE_ASSERTS - int num_fast_resend; -#endif - // the actual packet buffer std::uint8_t buf[1]; }; + static_assert((sizeof(packet) & 0x7) == 0, "packet structure size should be divisible by 8"); + struct packet_deleter { // deleter for std::unique_ptr void operator()(packet* p) const { TORRENT_ASSERT(p != nullptr); +#ifdef TORRENT_ADDRESS_SANITIZER + __asan_unpoison_memory_region(p, sizeof(packet)); +#endif p->~packet(); std::free(p); } @@ -112,7 +121,7 @@ namespace aux { using packet_ptr = std::unique_ptr; // internal - inline packet_ptr create_packet(int const size) + inline packet_ptr create_packet(int size) { packet* p = static_cast(std::malloc(sizeof(packet) + aux::numeric_cast(size))); if (p == nullptr) aux::throw_ex(); @@ -123,7 +132,7 @@ namespace aux { struct TORRENT_EXTRA_EXPORT packet_slab { - int const allocate_size; + int allocate_size; explicit packet_slab(int const alloc_size, std::size_t const limit = 10) : allocate_size(alloc_size) @@ -138,13 +147,21 @@ namespace aux { void try_push_back(packet_ptr &p) { if (m_storage.size() < m_limit) + { +#ifdef TORRENT_ADDRESS_SANITIZER + __asan_poison_memory_region(p.get(), sizeof(packet) + std::size_t(allocate_size)); +#endif m_storage.push_back(std::move(p)); + } } packet_ptr alloc() { if (m_storage.empty()) return create_packet(allocate_size); auto ret = std::move(m_storage.back()); +#ifdef TORRENT_ADDRESS_SANITIZER + __asan_unpoison_memory_region(ret.get(), sizeof(packet) + std::size_t(allocate_size)); +#endif m_storage.pop_back(); return ret; } @@ -212,6 +229,7 @@ namespace aux { if (allocate <= m_syn_slab.allocate_size) { return m_syn_slab.alloc(); } else if (allocate <= m_mtu_floor_slab.allocate_size) { return m_mtu_floor_slab.alloc(); } else if (allocate <= m_mtu_ceiling_slab.allocate_size) { return m_mtu_ceiling_slab.alloc(); } + return create_packet(allocate); } static constexpr int mtu_floor_size = TORRENT_INET_MIN_MTU - TORRENT_IPV4_HEADER - TORRENT_UDP_HEADER; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/resolver.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/resolver.hpp index ab9a7e60..fda44652 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/resolver.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/resolver.hpp @@ -76,7 +76,14 @@ struct TORRENT_EXTRA_EXPORT resolver final : resolver_interface std::vector
        addresses; }; + struct failed_dns_cache_entry + { + time_point last_seen; + error_code error; + }; + std::unordered_map m_cache; + std::unordered_map m_failed_cache; io_context& m_ios; // all lookups in this resolver are aborted on shutdown. diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_impl.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_impl.hpp index 34fbba2e..7df1f17e 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_impl.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_impl.hpp @@ -468,6 +468,10 @@ namespace aux { void close_connection(peer_connection* p) noexcept override; +#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS + void validate_setting(int const int_name, int const min, int const max); + void validate_settings(); +#endif void apply_settings_pack(std::shared_ptr pack) override; void apply_settings_pack_impl(settings_pack const& pack); session_settings const& settings() const override { return m_settings; } @@ -729,7 +733,7 @@ namespace aux { #if TORRENT_USE_I2P char const* i2p_session() const override { return m_i2p_conn.session_id(); } - proxy_settings i2p_proxy() const override; + std::string const& local_i2p_endpoint() const override { return m_i2p_conn.local_endpoint(); } void on_i2p_open(error_code const& ec); void open_new_incoming_i2p_connection(); diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_interface.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_interface.hpp index 84ce2963..ea5ccde2 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_interface.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/session_interface.hpp @@ -213,8 +213,8 @@ namespace aux { virtual proxy_settings proxy() const = 0; #if TORRENT_USE_I2P - virtual proxy_settings i2p_proxy() const = 0; virtual char const* i2p_session() const = 0; + virtual std::string const& local_i2p_endpoint() const = 0; #endif virtual void prioritize_connections(std::weak_ptr t) = 0; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/time.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/time.hpp index e3c14f47..9f2fcd5b 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/time.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/time.hpp @@ -37,12 +37,17 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/time.hpp" +#include // for std::time_t + namespace libtorrent { namespace aux { // returns the current time, as represented by time_point. The // resolution of this timer is about 100 ms. TORRENT_EXTRA_EXPORT time_point time_now(); TORRENT_EXTRA_EXPORT time_point32 time_now32(); + + TORRENT_EXTRA_EXPORT std::time_t to_time_t(time_point32 tp); + TORRENT_EXTRA_EXPORT time_point32 from_time_t(std::time_t t); } } #endif diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/torrent_list.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/torrent_list.hpp index 45dfa50e..5dc2573a 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/torrent_list.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/torrent_list.hpp @@ -214,6 +214,12 @@ struct torrent_list #if TORRENT_USE_INVARIANT_CHECKS void check_invariant() const { +#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS + // if we have many torrents, this would be an expensive + // invariant check, so don't run it in that case (unless we + // enabled expensive invariant checks) + if (m_array.size() > 100) return; +#endif std::set all_torrents; std::set all_indexed_torrents; #if !defined TORRENT_DISABLE_ENCRYPTION diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_socket_manager.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_socket_manager.hpp index 8ca521cc..37169f71 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_socket_manager.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_socket_manager.hpp @@ -119,6 +119,7 @@ namespace aux { int num_sockets() const { return int(m_utp_sockets.size()); } void defer_ack(utp_socket_impl* s); + void cancel_deferred_ack(utp_socket_impl* s); void subscribe_drained(utp_socket_impl* s); void restrict_mtu(int const mtu) diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_stream.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_stream.hpp index 2259f3cd..e37ec32b 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_stream.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/aux_/utp_stream.hpp @@ -248,13 +248,15 @@ struct TORRENT_EXTRA_EXPORT utp_stream , error_code const& ec, bool shutdown); static void on_connect(utp_stream* self, error_code const& ec, bool shutdown); static void on_close_reason(utp_stream* self, close_reason_t reason); + static void on_writeable(utp_stream* self, error_code const& ec); void add_read_buffer(void* buf, int len); void issue_read(); void add_write_buffer(void const* buf, int len); bool check_fin_sent() const; void issue_write(); - std::size_t read_some(bool clear_buffers); + void subscribe_writeable(); + std::size_t read_some(bool clear_buffers, error_code& ec); std::size_t write_some(bool clear_buffers); int send_delay() const; @@ -329,6 +331,25 @@ struct TORRENT_EXTRA_EXPORT utp_stream issue_read(); } + template + void async_wait_read(Handler handler) + { + if (m_impl == nullptr) + { + post(m_io_service, std::bind(std::move(handler), boost::asio::error::not_connected, std::size_t(0))); + return; + } + + TORRENT_ASSERT(!m_read_handler); + if (m_read_handler) + { + post(m_io_service, std::bind(std::move(handler), boost::asio::error::operation_not_supported, std::size_t(0))); + return; + } + m_read_handler = std::move(handler); + issue_read(); + } + template void open(Protocol const&, error_code&) { m_open = true; } @@ -364,7 +385,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream buf_size += i->size(); #endif } - std::size_t ret = read_some(true); + std::size_t ret = read_some(true, ec); TORRENT_ASSERT(ret <= buf_size); TORRENT_ASSERT(ret > 0); return ret; @@ -476,6 +497,35 @@ struct TORRENT_EXTRA_EXPORT utp_stream issue_write(); } + template + void async_wait_write(Handler handler) + { + if (m_impl == nullptr) + { + post(m_io_service, std::bind(std::move(handler) + , boost::asio::error::not_connected)); + return; + } + + TORRENT_ASSERT(!m_writeable_handler); + if (m_writeable_handler) + { + post(m_io_service, std::bind(std::move(handler) + , boost::asio::error::operation_not_supported)); + return; + } + + if (check_fin_sent()) + { + // we can't send more data after closing the socket + post(m_io_service, std::bind(std::move(handler) + , boost::asio::error::broken_pipe)); + return; + } + m_writeable_handler = std::move(handler); + subscribe_writeable(); + } + #if BOOST_VERSION >= 106600 // Compatiblity with the async_wait method introduced in boost 1.66 @@ -486,13 +536,11 @@ struct TORRENT_EXTRA_EXPORT utp_stream switch(type) { case wait_read: - async_read_some(boost::asio::null_buffers() - , [handler](error_code ec, size_t) { handler(std::move(ec)); }); + async_wait_read([handler](error_code ec, size_t) { handler(std::move(ec)); }); break; case wait_write: - async_write_some(boost::asio::null_buffers() - , [handler](error_code ec, size_t) { handler(std::move(ec)); }); + async_wait_write(std::move(handler)); break; case wait_error: @@ -510,6 +558,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream std::function m_connect_handler; std::function m_read_handler; std::function m_write_handler; + std::function m_writeable_handler; io_context& m_io_service; utp_socket_impl* m_impl; @@ -588,6 +637,7 @@ struct utp_socket_impl bool should_delete() const; tcp::endpoint remote_endpoint(error_code& ec) const; std::size_t available() const; + void close(); // returns true if there were handlers cancelled // if it returns false, we can detach immediately bool destroy(); @@ -603,7 +653,7 @@ struct utp_socket_impl enum packet_flags_t { pkt_ack = 1, pkt_fin = 2 }; bool send_pkt(int flags = 0); bool resend_packet(packet* p, bool fast_resend = false); - void send_reset(utp_header const* ph); + void send_reset(std::uint16_t ack_nr); std::pair parse_sack(std::uint16_t packet_ack, std::uint8_t const* ptr , int size, time_point now); void parse_close_reason(std::uint8_t const* ptr, int size); @@ -616,15 +666,16 @@ struct utp_socket_impl void do_ledbat(int acked_bytes, int delay, int in_flight); int packet_timeout() const; bool test_socket_state(); - void maybe_trigger_receive_callback(); - void maybe_trigger_send_callback(); + void maybe_trigger_receive_callback(error_code const& ec); + void maybe_trigger_send_callback(error_code const& ec); + void maybe_trigger_writeable_callback(error_code const& ec); bool cancel_handlers(error_code const& ec, bool shutdown); bool consume_incoming_data( utp_header const* ph, std::uint8_t const* ptr, int payload_size, time_point now); void update_mtu_limits(); void experienced_loss(std::uint32_t seq_nr, time_point now); - void send_ack(); + void send_deferred_ack(); void socket_drained(); void set_userdata(utp_stream* s) { m_userdata = s; } @@ -650,12 +701,13 @@ struct utp_socket_impl void issue_read(); void issue_write(); + void subscribe_writeable(); bool check_fin_sent() const; void do_connect(tcp::endpoint const& ep); - std::size_t read_some(bool const clear_buffers); + std::size_t read_some(bool const clear_buffers, error_code& ec); std::size_t write_some(bool const clear_buffers); // Warning: non-blocking int receive_buffer_size() const { return m_receive_buffer_size; } @@ -761,6 +813,7 @@ struct utp_socket_impl // connect operation. i.e. is there upper layer subscribed to these events. bool m_read_handler = false; bool m_write_handler = false; + bool m_writeable_handler = false; bool m_connect_handler = false; // the address of the remote endpoint @@ -905,7 +958,7 @@ struct utp_socket_impl // valid if m_eof is true. We should not accept // any packets beyond this sequence number from the // other end - std::uint16_t m_eof_seq_nr = 0; + std::uint16_t m_in_eof_seq_nr = 0; // this is the lowest sequence number that, when lost, // will cause the window size to be cut in half @@ -948,7 +1001,14 @@ struct utp_socket_impl std::uint8_t m_state:3; // this is set to true when we receive a fin - bool m_eof:1; + // The incoming stream is being closed at sequence number + // indicated by m_in_eof_seq_nr + bool m_in_eof:1; + + // this is true when the application has called close() on the socket. + // at this point, we will send a FIN at the current sequence number, + // and will not allow it to be incremented any further + bool m_out_eof:1; // is this socket state attached to a user space socket? bool m_attached:1; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/bencode.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/bencode.hpp index dd78725a..ceb93b4a 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/bencode.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/bencode.hpp @@ -365,7 +365,7 @@ namespace aux { // function assumes the value_type of the iterator is a ``char``. // In order to encode entry ``e`` into a buffer, do:: // - // std::vector buffer; + // std::vector buf; // bencode(std::back_inserter(buf), e); // // .. _OutputIterator: https://en.cppreference.com/w/cpp/named_req/OutputIterator diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/bitfield.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/bitfield.hpp index fd088429..44a08295 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/bitfield.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/bitfield.hpp @@ -134,6 +134,13 @@ namespace libtorrent { return (size() + 31) / 32; } + // returns the number of bytes needed to represent all bits in this + // bitfield + int num_bytes() const noexcept + { + return (size() + 7) / 8; + } + // returns true if the bitfield has zero size. bool empty() const noexcept { return size() == 0; } @@ -171,6 +178,8 @@ namespace libtorrent { // returns the index to the last cleared bit in the bitfield, i.e. 0 bit. int find_last_clear() const noexcept; + bool operator==(lt::bitfield const& rhs) const; + // internal struct const_iterator { diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/config.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/config.hpp index 52344107..dd115736 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/config.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/config.hpp @@ -43,7 +43,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/disable_warnings_push.hpp" +#if !defined __MINGW64__ && !defined __MINGW32__ #define _FILE_OFFSET_BITS 64 +#endif #include @@ -61,6 +63,21 @@ POSSIBILITY OF SUCH DAMAGE. // format codes are. So we need to disable those for mingw targets #pragma GCC diagnostic ignored "-Wformat" #pragma GCC diagnostic ignored "-Wformat-extra-args" +// Mingw does not like friend declarations of dllexport functions. This +// suppresses those warnings +#pragma GCC diagnostic ignored "-Wattributes" +#endif + +// This is the GCC indication of building with address sanitizer +#if defined __SANITIZE_ADDRESS__ && __SANITIZE_ADDRESS__ +#define TORRENT_ADDRESS_SANITIZER 1 +#endif + +// This is the clang indication of building with address sanitizer +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define TORRENT_ADDRESS_SANITIZER 1 +#endif #endif #if defined __GNUC__ @@ -127,7 +144,11 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_USE_EXECINFO 1 #endif +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 +// this is used for the ip_change_notifier on macOS, which isn't supported on +// 10.6 and earlier #define TORRENT_USE_SYSTEMCONFIGURATION 1 +#endif #if TARGET_OS_IPHONE #define TORRENT_USE_SC_NETWORK_REACHABILITY 1 @@ -567,19 +588,6 @@ POSSIBILITY OF SUCH DAMAGE. #error "invariant checks cannot be enabled without asserts" #endif -// for non-exception builds -#ifdef BOOST_NO_EXCEPTIONS -#define TORRENT_TRY if (true) -#define TORRENT_CATCH(x) else if (false) -#define TORRENT_CATCH_ALL else if (false) -#define TORRENT_DECLARE_DUMMY(x, y) x y -#else -#define TORRENT_TRY try -#define TORRENT_CATCH(x) catch(x) -#define TORRENT_CATCH_ALL catch(...) -#define TORRENT_DECLARE_DUMMY(x, y) -#endif // BOOST_NO_EXCEPTIONS - // SSE is x86 / amd64 specific. On top of that, we only // know how to access it on msvc and gcc (and gcc compatibles). // GCC requires the user to enable SSE support in order for diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/create_torrent.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/create_torrent.hpp index 889e297a..09c300f9 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/create_torrent.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/create_torrent.hpp @@ -200,6 +200,9 @@ namespace libtorrent { // This flag is here for backwards compatibility. static constexpr create_flags_t canonical_files_no_tail_padding = 9_bit; + // hidden + static constexpr create_flags_t allow_odd_piece_size = 31_bit; + // The ``piece_size`` is the size of each piece in bytes. It must be a // power of 2 and a minimum of 16 kiB. If a piece size of 0 is // specified, a piece_size will be set automatically. diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/file_storage.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/file_storage.hpp index 08145fe4..d5c18be9 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/file_storage.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/file_storage.hpp @@ -451,6 +451,10 @@ namespace aux { // returns the number of blocks in the specified piece, for v2 torrents. int blocks_in_piece2(piece_index_t index) const; + // returns the number of blocks there are in the typical piece. There + // may be fewer in the last piece) + int blocks_per_piece() const; + // set and get the name of this torrent. For multi-file torrents, this is also // the name of the root directory all the files are stored in. void set_name(std::string const& n) { m_name = n; } diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/hash_picker.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/hash_picker.hpp index 3ae4c34b..bb5b1019 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/hash_picker.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/hash_picker.hpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/bitfield.hpp" #include "libtorrent/time.hpp" +#include "libtorrent/index_range.hpp" #include #include @@ -64,11 +65,22 @@ namespace libtorrent }; explicit set_block_hash_result(result s) : status(s), first_verified_block(0), num_verified(0) {} - set_block_hash_result(int first_block, int num) : status(result::success), first_verified_block(first_block), num_verified(num) {} + set_block_hash_result(result st, int first_block, int num) : status(st), first_verified_block(first_block), num_verified(num) {} + index_range piece_range( + piece_index_t const piece + , int const blocks_per_piece) const + { + using delta = piece_index_t::diff_type; + piece_index_t const start = piece + delta(first_verified_block / blocks_per_piece); + piece_index_t const end = start + delta(num_verified / blocks_per_piece); + return {start, end}; + } + + static set_block_hash_result success(int first_block, int num) { return set_block_hash_result(result::success, first_block, num); } static set_block_hash_result unknown() { return set_block_hash_result(result::unknown); } static set_block_hash_result block_hash_failed() { return set_block_hash_result(result::block_hash_failed); } - static set_block_hash_result piece_hash_failed() { return set_block_hash_result(result::piece_hash_failed); } + static set_block_hash_result piece_hash_failed(int first_block, int num) { return set_block_hash_result(result::piece_hash_failed, first_block, num); } result status; // if status is success, this will hold the index of the first verified diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/http_seed_connection.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/http_seed_connection.hpp index 55ab8913..3d269ace 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/http_seed_connection.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/http_seed_connection.hpp @@ -87,6 +87,8 @@ namespace libtorrent { // will be invalid. piece_block_progress downloading_piece_progress() const override; + void disable(error_code const& ec); + // this is const since it's used as a key in the web seed list in the torrent // if it's changed referencing back into that list will fail const std::string m_url; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/i2p_stream.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/i2p_stream.hpp index 2f201eb6..ca0ec74a 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/i2p_stream.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/i2p_stream.hpp @@ -101,6 +101,14 @@ namespace libtorrent { { return i2p_category(); } #endif +struct i2p_session_options +{ + int m_inbound_quantity = 3; + int m_outbound_quantity = 3; + int m_inbound_length = 3; + int m_outbound_length = 3; +}; + struct i2p_stream : proxy_base { explicit i2p_stream(io_context& io_context); @@ -123,10 +131,17 @@ struct i2p_stream : proxy_base void set_command(command_t c) { m_command = c; } + void set_session_options(i2p_session_options const& session_options) + { + m_session_options = session_options; + } + void set_session_id(char const* id) { m_id = id; } + void set_local_i2p_endpoint(string_view d) { m_local = d.to_string(); } + std::string const& local_i2p_endpoint() const { return m_local; } void set_destination(string_view d) { m_dest = d.to_string(); } - std::string const& destination() { return m_dest; } + std::string const& destination() const { return m_dest; } template void async_connect(endpoint_type const&, Handler h) @@ -193,7 +208,7 @@ struct i2p_stream : proxy_base // send hello command m_state = read_hello_response; - static const char cmd[] = "HELLO VERSION MIN=3.0 MAX=3.0\n"; + static const char cmd[] = "HELLO VERSION MIN=3.1 MAX=3.1\n"; ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line"); async_write(m_sock, boost::asio::buffer(cmd, sizeof(cmd) - 1), wrap_allocator( @@ -232,11 +247,6 @@ struct i2p_stream : proxy_base ADD_OUTSTANDING_ASYNC("i2p_stream::read_line"); // read another byte from the socket m_buffer.resize(read_pos + 1); - async_read(m_sock, boost::asio::buffer(&m_buffer[read_pos], 1), wrap_allocator( - [this](error_code const& ec, std::size_t, Handler hn) { - start_read_line(ec, std::move(hn)); - }, std::move(h))); - async_read(m_sock, boost::asio::buffer(&m_buffer[read_pos], 1), wrap_allocator( [this](error_code const& ec, std::size_t, Handler hn) { read_line(ec, std::move(hn)); @@ -282,7 +292,8 @@ struct i2p_stream : proxy_base break; } - string_view remaining(m_buffer.data(), m_buffer.size()); + TORRENT_ASSERT(m_buffer[int(m_buffer.size()) - 1] == '\0'); + string_view remaining(m_buffer.data(), m_buffer.size() - 1); string_view token; std::tie(token, remaining) = split_string(remaining, ' '); @@ -301,7 +312,16 @@ struct i2p_stream : proxy_base std::tie(name, remaining) = split_string(remaining, '='); if (name.empty()) break; string_view value; - std::tie(value, remaining) = split_string(remaining, ' '); + if (remaining[0] == '"') + { + std::tie(value, remaining) = split_string(remaining.substr(1), '"'); + if (value.empty()) { handle_error(invalid_response, h); return; } + value.remove_suffix(1); + } + else + { + std::tie(value, remaining) = split_string(remaining, ' '); + } if (value.empty()) { handle_error(invalid_response, h); return; } if ("RESULT"_sv == name) @@ -342,16 +362,10 @@ struct i2p_stream : proxy_base } error_code ec(result, i2p_category()); - switch (result) + if (ec) { - case i2p_error::no_error: - case i2p_error::invalid_key: - break; - default: - { - handle_error (ec, h); - return; - } + std::forward(h)(ec); + return; } switch (m_state) @@ -371,14 +385,14 @@ struct i2p_stream : proxy_base case cmd_none: case cmd_name_lookup: case cmd_incoming: - h(e); + std::forward(h)(ec); std::vector().swap(m_buffer); } break; case read_connect_response: case read_session_create_response: case read_name_lookup_response: - h(ec); + std::forward(h)(ec); std::vector().swap(m_buffer); break; case read_accept_response: @@ -408,7 +422,7 @@ struct i2p_stream : proxy_base ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line"); async_write(m_sock, boost::asio::buffer(cmd, std::size_t(size)), wrap_allocator( [this](error_code const& ec, std::size_t, Handler hn) { - read_line(ec, std::move(hn)); + start_read_line(ec, std::move(hn)); }, std::move(h))); } @@ -432,8 +446,11 @@ struct i2p_stream : proxy_base TORRENT_ASSERT(m_magic == 0x1337); m_state = read_session_create_response; char cmd[400]; - int size = std::snprintf(cmd, sizeof(cmd), "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT\n" - , m_id); + int size = std::snprintf(cmd, sizeof(cmd), + "SESSION CREATE STYLE=STREAM ID=%s DESTINATION=TRANSIENT SIGNATURE_TYPE=7 " + "inbound.quantity=%d outbound.quantity=%d inbound.length=%d outbound.length=%d\n", + m_id, m_session_options.m_inbound_quantity, m_session_options.m_outbound_quantity, + m_session_options.m_inbound_length, m_session_options.m_outbound_length); ADD_OUTSTANDING_ASYNC("i2p_stream::start_read_line"); async_write(m_sock, boost::asio::buffer(cmd, std::size_t(size)), wrap_allocator( [this](error_code const& ec, std::size_t, Handler hn) { @@ -443,10 +460,13 @@ struct i2p_stream : proxy_base // send and receive buffer aux::noexcept_movable> m_buffer; - char const* m_id; + char const* m_id = nullptr; std::string m_dest; + std::string m_local; std::string m_name_lookup; + i2p_session_options m_session_options; + enum state_t : std::uint8_t { read_hello_response, @@ -459,7 +479,7 @@ struct i2p_stream : proxy_base command_t m_command; state_t m_state; #if TORRENT_USE_ASSERTS - int m_magic; + int m_magic = 0x1337; #endif }; @@ -480,7 +500,8 @@ class i2p_connection && m_state != sam_connecting; } template - void open(std::string const& hostname, int port, Handler handler) + void open(std::string const& hostname, int port, + i2p_session_options const& session_options, Handler handler) { // we already seem to have a session to this SAM router if (m_hostname == hostname @@ -504,6 +525,7 @@ class i2p_connection m_sam_socket->set_proxy(m_hostname, m_port); m_sam_socket->set_command(i2p_stream::cmd_create_session); m_sam_socket->set_session_id(m_session_id.c_str()); + m_sam_socket->set_session_options(session_options); ADD_OUTSTANDING_ASYNC("i2p_stream::on_sam_connect"); m_sam_socket->async_connect(tcp::endpoint(), wrap_allocator( @@ -513,6 +535,7 @@ class i2p_connection } void close(error_code&); + // TODO: make this a string_view char const* session_id() const { return m_session_id.c_str(); } std::string const& local_endpoint() const { return m_i2p_local_endpoint; } diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/observer.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/observer.hpp index a0340129..0ef35a1a 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/observer.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/observer.hpp @@ -63,6 +63,7 @@ struct TORRENT_EXTRA_EXPORT observer : m_algorithm(std::move(a)) , m_id(id) { + TORRENT_ASSERT(!m_was_sent); TORRENT_ASSERT(m_algorithm); set_target(ep); } @@ -105,13 +106,27 @@ struct TORRENT_EXTRA_EXPORT observer void set_id(node_id const& id); node_id const& id() const { return m_id; } + // an entry that has the queried flag set will have incremented the m_invoke_count + // and is supposed to decrement it, once a response is received. It + // will also have sent its query to its node static constexpr observer_flags_t flag_queried = 0_bit; static constexpr observer_flags_t flag_initial = 1_bit; static constexpr observer_flags_t flag_no_id = 2_bit; + // after a short timeout, we may increase the branch factor and set + // this flag. We still wait for the full timeout for a response. + // Incrementing the branch factor is a middle-ground of no longer + // having much faith in this node responding (so we allow another query + // to use its "slot"). When the request completes (either by receiving + // a response or timing out), we need to restore the branch factor by + // decrementing it. static constexpr observer_flags_t flag_short_timeout = 3_bit; + // a node static constexpr observer_flags_t flag_failed = 4_bit; + // This determines whether the m_addr union has the IPv4 or IPv6 address active static constexpr observer_flags_t flag_ipv6_address = 5_bit; + // This means we have received a response from this node static constexpr observer_flags_t flag_alive = 6_bit; + // the request has been cancelled static constexpr observer_flags_t flag_done = 7_bit; protected: diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/traversal_algorithm.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/traversal_algorithm.hpp index 653a0a8c..71f0019e 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/traversal_algorithm.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/kademlia/traversal_algorithm.hpp @@ -48,6 +48,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace libtorrent { @@ -65,8 +66,7 @@ struct TORRENT_EXTRA_EXPORT traversal_algorithm void traverse(node_id const& id, udp::endpoint const& addr); void finished(observer_ptr o); - static constexpr traversal_flags_t prevent_request = 0_bit; - static constexpr traversal_flags_t short_timeout = 1_bit; + static constexpr traversal_flags_t short_timeout = 0_bit; void failed(observer_ptr o, traversal_flags_t flags = {}); virtual ~traversal_algorithm(); @@ -88,10 +88,16 @@ struct TORRENT_EXTRA_EXPORT traversal_algorithm node& get_node() const { return m_node; } + void abort() { m_abort = true; } + #ifndef TORRENT_DISABLE_LOGGING std::uint32_t id() const { return m_id; } #endif +#if TORRENT_USE_INVARIANT_CHECKS + void check_invariant() const; +#endif + protected: std::shared_ptr self() @@ -141,6 +147,10 @@ struct TORRENT_EXTRA_EXPORT traversal_algorithm // and leak bool m_done = false; + // abort is set when we're cancelling the remaining lookups. Whenever a + // lookup completes, we won't issue another one + bool m_abort = false; + #ifndef TORRENT_DISABLE_LOGGING // this is a unique ID for this specific traversal_algorithm instance, // just used for logging @@ -153,6 +163,9 @@ struct TORRENT_EXTRA_EXPORT traversal_algorithm #ifndef TORRENT_DISABLE_LOGGING void log_timeout(observer_ptr const& o, char const* prefix) const; #endif +#if TORRENT_USE_ASSERTS + bool m_initialized = false; +#endif }; void look_for_nodes(char const* nodes_key, udp const& protocol diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/peer.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/peer.hpp index 9d3b0e3c..a00bf9a9 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/peer.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/peer.hpp @@ -65,6 +65,12 @@ namespace libtorrent { std::uint16_t port; }; +#if TORRENT_USE_I2P + struct i2p_peer_entry + { + sha256_hash destination; + }; +#endif } #endif // TORRENT_PEER_HPP_INCLUDED diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection.hpp index c0452da2..058734bc 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection.hpp @@ -492,6 +492,11 @@ namespace aux { tcp::endpoint const& remote() const override { return m_remote; } tcp::endpoint local_endpoint() const override { return m_local; } +#if TORRENT_USE_I2P + std::string const& destination() const override; + std::string const& local_i2p_endpoint() const override; +#endif + typed_bitfield const& get_bitfield() const; std::vector const& allowed_fast(); std::vector const& suggested_pieces() const { return m_suggested_pieces; } @@ -639,6 +644,7 @@ namespace aux { // picker, allowing another peer to request it immediately void cancel_request(piece_block const& b, bool force = false); void send_block_requests(); + void send_block_requests_impl(); void assign_bandwidth(int channel, int amount) override; @@ -1151,7 +1157,8 @@ namespace aux { // pick any pieces from this peer bool m_no_download:1; - // 1 bit + // indicates that we want to request more blocks from this peer + bool m_deferred_send_block_requests:1; // set to true while we're trying to holepunch bool m_holepunch_mode:1; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection_interface.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection_interface.hpp index 489afb34..ef8b0fe6 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection_interface.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/peer_connection_interface.hpp @@ -55,6 +55,10 @@ namespace libtorrent { static constexpr disconnect_severity_t failure{1}; static constexpr disconnect_severity_t peer_error{2}; +#if TORRENT_USE_I2P + virtual std::string const& destination() const = 0; + virtual std::string const& local_i2p_endpoint() const = 0; +#endif virtual tcp::endpoint const& remote() const = 0; virtual tcp::endpoint local_endpoint() const = 0; virtual void disconnect(error_code const& ec diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/peer_info.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/peer_info.hpp index c1f10329..451b0995 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/peer_info.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/peer_info.hpp @@ -249,7 +249,7 @@ TORRENT_VERSION_NAMESPACE_2 int payload_up_speed; int payload_down_speed; - // the peer's id as used in the bit torrent protocol. This id can be used + // the peer's id as used in the bittorrent protocol. This id can be used // to extract 'fingerprints' from the peer. Sometimes it can tell you // which client the peer is using. See identify_client()_ peer_id pid; @@ -389,7 +389,8 @@ TORRENT_VERSION_NAMESPACE_2 #endif // the IP-address to this peer. The type is an asio endpoint. For - // more info, see the asio_ documentation. + // more info, see the asio_ documentation. This field is not valid for + // i2p peers. Instead use the i2p_destination() function. // // .. _asio: http://asio.sourceforge.net/asio-0.3.8/doc/asio/reference.html tcp::endpoint ip; @@ -397,6 +398,7 @@ TORRENT_VERSION_NAMESPACE_2 // the IP and port pair the socket is bound to locally. i.e. the IP // address of the interface it's going out over. This may be useful for // multi-homed clients with multiple interfaces to the internet. + // This field is not valid for i2p peers. tcp::endpoint local_endpoint; // The peer is not waiting for any external events to @@ -423,6 +425,15 @@ TORRENT_VERSION_NAMESPACE_2 bandwidth_state_flags_t read_state; bandwidth_state_flags_t write_state; +#if TORRENT_USE_I2P + // If this peer is an i2p peer, this function returns the destination + // address of the peer + sha256_hash i2p_destination() const; + + // internal + void set_i2p_destination(sha256_hash dest); +#endif + #if TORRENT_ABI_VERSION == 1 TORRENT_DEPRECATED static constexpr bandwidth_state_flags_t bw_torrent = bw_limit; TORRENT_DEPRECATED static constexpr bandwidth_state_flags_t bw_global = bw_limit; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/peer_list.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/peer_list.hpp index 93051264..3fe0711b 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/peer_list.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/peer_list.hpp @@ -143,7 +143,7 @@ namespace libtorrent { void apply_ip_filter(ip_filter const& filter, torrent_state* state , std::vector
        & banned); void apply_port_filter(port_filter const& filter, torrent_state* state - , std::vector
        & banned); + , std::vector& banned); void set_seed(torrent_peer* p, bool s); diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/settings_pack.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/settings_pack.hpp index c899d1cd..0446f2b6 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/settings_pack.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/settings_pack.hpp @@ -363,7 +363,10 @@ namespace aux { proxy_password, // sets the i2p_ SAM bridge to connect to. set the port with the - // ``i2p_port`` setting. + // ``i2p_port`` setting. Unless this is set, i2p torrents are not + // supported. This setting is separate from the other proxy settings + // since i2p torrents and their peers are orthogonal. You can have + // i2p peers as well as regular peers via a proxy. // // .. _i2p: http://www.i2p2.de i2p_hostname, @@ -1435,6 +1438,11 @@ namespace aux { // default (i.e. don't change the buffer sizes). // The socket buffer sizes are changed using setsockopt() with // SOL_SOCKET/SO_RCVBUF and SO_SNDBUFFER. + // + // Note that uTP peers share a single UDP socket buffer for each of the + // ``listen_interfaces``, along with DHT and UDP tracker traffic. + // If the buffer size is too small for the combined traffic through the + // socket, packets may be dropped. recv_socket_buffer_size, send_socket_buffer_size, @@ -2048,6 +2056,18 @@ namespace aux { // operations. This file size limit is specified in 16 kiB blocks. mmap_file_size_cutoff, + // Configures the SAM session + // quantity of I2P inbound and outbound tunnels [1..16]. + // number of hops for I2P inbound and outbound tunnels [0..7] + // Changing these will not trigger a reconnect to the SAM bridge, + // they will take effect the next time the SAM connection is + // re-established (by restarting or changing i2p_hostname or + // i2p_port). + i2p_inbound_quantity, + i2p_outbound_quantity, + i2p_inbound_length, + i2p_outbound_length, + max_int_setting_internal }; @@ -2206,8 +2226,13 @@ namespace aux { // authorization. The username and password will be sent to the proxy. http_pw, - // route through a i2p SAM proxy +#if TORRENT_USE_I2P + // internal + // This is used internally to communicate with the + // http_tracker_connection. To configure an i2p SAM bridge, set + // i2p_hostname and i2p_port. i2p_proxy +#endif }; private: diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/torrent.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/torrent.hpp index d404efd8..116d264a 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/torrent.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/torrent.hpp @@ -208,11 +208,19 @@ namespace libtorrent { // web seed from resolving to any local network IPs. bool no_local_ips = false; + // This means we want to preserve the web seed in resume data, but not + // use it for the remainder of this session. For example: + // this web seed maye have responded with a redirect. The redirected + // URLs have been added as ephemeral. If an ephemeral URL is redirected, + // its web seed entry is removed. It could also mean we don't support + // the URL protocol, but maybe another client may support it. + bool disabled = false; + // if the web server doesn't support keepalive or a block request was // interrupted, the block received so far is kept here for the next // connection to pick up peer_request restart_request = { piece_index_t(-1), -1, -1}; - std::vector restart_piece; + aux::vector restart_piece; // this maps file index to a URL it has been redirected to. If an entry is // missing, it means it has not been redirected and the full path should @@ -239,6 +247,7 @@ namespace libtorrent { removed = std::move(rhs.removed); ephemeral = std::move(rhs.ephemeral); no_local_ips = std::move(rhs.no_local_ips); + disabled = std::move(rhs.disabled); restart_request = std::move(rhs.restart_request); restart_piece = std::move(rhs.restart_piece); redirects = std::move(rhs.redirects); @@ -387,6 +396,8 @@ namespace libtorrent { update_gauge(); } + bool is_added() const { return m_added; } + // returns which stats gauge this torrent currently // has incremented. int current_stats_state() const; @@ -534,6 +545,7 @@ namespace libtorrent { void received_synack(bool ipv6); void set_ip_filter(std::shared_ptr ipf); + void privileged_port_updated(); void port_filter_updated(); ip_filter const* get_ip_filter() { return m_ip_filter.get(); } @@ -544,6 +556,7 @@ namespace libtorrent { void handle_disk_error(string_view job_name , storage_error const& error, peer_connection* c = nullptr , disk_class rw = disk_class::none); + void handle_inconsistent_hashes(piece_index_t piece); void clear_error(); void set_error(error_code const& ec, file_index_t file); @@ -577,12 +590,19 @@ namespace libtorrent { void force_recheck(); void save_resume_data(resume_data_flags_t flags); - bool need_save_resume_data() const { return m_need_save_resume_data; } + bool need_save_resume_data(resume_data_flags_t flags) const + { + return bool(m_need_save_resume_data & flags); + } - void set_need_save_resume() + void set_need_save_resume(resume_data_flags_t const flag) { - if (m_need_save_resume_data) return; - m_need_save_resume_data = true; + // every category sets this bit. TODO: make this flag a combination + // of the other ones + m_need_save_resume_data |= torrent_handle::only_if_modified; + + if (m_need_save_resume_data & flag) return; + m_need_save_resume_data |= flag; state_updated(); } @@ -600,6 +620,7 @@ namespace libtorrent { #endif #endif // TORRENT_ABI_VERSION + void post_piece_availability(); void piece_availability(aux::vector& avail) const; void set_piece_priority(piece_index_t index, download_priority_t priority); @@ -626,6 +647,7 @@ namespace libtorrent { void update_piece_priorities( aux::vector const& file_prios); + void post_status(status_flags_t flags); void status(torrent_status* st, status_flags_t flags); // this torrent changed state, if the user is subscribing to @@ -633,6 +655,7 @@ namespace libtorrent { void state_updated(); void file_progress(aux::vector& fp, file_progress_flags_t flags); + void post_file_progress(file_progress_flags_t flags); #if TORRENT_ABI_VERSION == 1 void use_interface(std::string net_interface); @@ -664,7 +687,12 @@ namespace libtorrent { // -------------------------------------------- // PEER MANAGEMENT + // A web seed entry that's added because of a redirect is flagged as + // ephemeral. We don't want to save these in the resume data. static constexpr web_seed_flag_t ephemeral = 0_bit; + // A web seed entry with this flag set is not allowed to resolve to an + // IP on a local network. This is part of SSRF mitigation, as it may be + // malicious static constexpr web_seed_flag_t no_local_ips = 1_bit; // add_web_seed won't add duplicates. If we have already added an entry @@ -676,12 +704,10 @@ namespace libtorrent { , web_seed_flag_t flags = {}); void remove_web_seed(std::string const& url, web_seed_t::type_t type); - void disconnect_web_seed(peer_connection* p); void retry_web_seed(peer_connection* p, boost::optional retry = boost::none); - void remove_web_seed_conn(peer_connection* p, error_code const& ec - , operation_t op, disconnect_severity_t error = peer_connection_interface::normal); + void remove_web_seed_conn(peer_connection* peer); std::set web_seeds(web_seed_entry::type_t type) const; @@ -747,8 +773,10 @@ namespace libtorrent { #if TORRENT_ABI_VERSION == 1 void get_full_peer_list(std::vector* v) const; #endif + void post_peer_info(); void get_peer_info(std::vector* v); void get_download_queue(std::vector* queue) const; + void post_download_queue(); void update_auto_sequential(); private: @@ -867,7 +895,7 @@ namespace libtorrent { // called when we learn that we have a piece // only once per piece - void we_have(piece_index_t index); + void we_have(piece_index_t index, bool loading_resume = false); // process the v2 block hashes for a piece boost::tribool on_blocks_hashed(piece_index_t piece @@ -929,7 +957,7 @@ namespace libtorrent { #if TORRENT_USE_I2P void on_i2p_resolve(error_code const& ec, char const* dest); - bool is_i2p() const { return m_torrent_file && m_torrent_file->is_i2p(); } + bool is_i2p() const { return m_i2p; } #endif // this is the asio callback that is called when a name @@ -1089,6 +1117,7 @@ namespace libtorrent { std::vector> get_piece_layers() const; + void post_trackers(); std::vector trackers() const; // this sets all the "enabled" states on all trackers, giving them @@ -1632,16 +1661,13 @@ namespace libtorrent { // from a non-downloading/seeding state, the torrent is paused. bool m_stop_when_ready:1; - // set to false when saving resume data. Set to true - // whenever something is downloaded - bool m_need_save_resume_data:1; - // when this is true, this torrent participates in the DHT bool m_enable_dht:1; // when this is true, this torrent participates in local service discovery bool m_enable_lsd:1; + bool m_i2p:1; // ---- // total time we've been available as a seed on this torrent. @@ -1656,7 +1682,8 @@ namespace libtorrent { // the maximum number of uploads for this torrent std::uint32_t m_max_uploads:24; - // 8 bits free + // bits set to indicate which category of resume data state has updated + resume_data_flags_t m_need_save_resume_data; // ---- diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_flags.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_flags.hpp index 12d06808..90ee4205 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_flags.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_flags.hpp @@ -211,8 +211,10 @@ namespace torrent_flags { constexpr torrent_flags_t override_web_seeds = 12_bit; // if this flag is set (which it is by default) the torrent will be - // considered needing to save its resume data immediately as it's - // added. New torrents that don't have any resume data should do that. + // considered needing to save its resume data immediately, in the + // category if_metadata_changed. See resume_data_flags_t and + // save_resume_data() for details. + // // This flag is cleared by a successful call to save_resume_data() // This flag is not saved by write_resume_data(), since it represents an // ephemeral state of a running torrent. @@ -291,6 +293,18 @@ namespace torrent_flags { // (dont_download). constexpr torrent_flags_t default_dont_download = 23_bit; + // this flag makes the torrent be considered an "i2p torrent" for purposes + // of the allow_i2p_mixed setting. When mixing regular peers and i2p peers + // is disabled, i2p torrents won't add normal peers to its peer list. + // Note that non i2p torrents may still allow i2p peers (on the off-chance + // that a tracker return them and the session is configured with a SAM + // connection). + // This flag is set automatically when adding a torrent that has at least + // one tracker whose hostname ends with .i2p. + // It's also set by parse_magnet_uri() if the tracker list contains such + // URL. + constexpr torrent_flags_t i2p_torrent = 24_bit; + // all torrent flags combined. Can conveniently be used when creating masks // for flags constexpr torrent_flags_t all = torrent_flags_t::all(); diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_handle.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_handle.hpp index 8b5265e0..6ffd49fb 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_handle.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_handle.hpp @@ -182,6 +182,8 @@ namespace aux { // .. warning:: This is a pointer that points to an array // that's owned by the session object. The next time // get_download_queue() is called, it will be invalidated. + // In the case of piece_info_alert, these pointers point into the alert + // object itself, and will be invalidated when the alert destruct. block_info const* blocks; #if TORRENT_ABI_VERSION == 1 @@ -239,7 +241,7 @@ namespace aux { friend struct aux::session_impl; friend struct session_handle; friend struct torrent; - friend TORRENT_EXPORT std::size_t hash_value(torrent_handle const& th); + TORRENT_EXPORT friend std::size_t hash_value(torrent_handle const& th); // constructs a torrent handle that does not refer to a torrent. // i.e. is_valid() will return false. @@ -319,11 +321,19 @@ namespace aux { void get_full_peer_list(std::vector& v) const; #endif - // takes a reference to a vector that will be cleared and filled with one - // entry for each peer connected to this torrent, given the handle is - // valid. If the torrent_handle is invalid, it will throw - // system_error exception. Each entry in the vector contains - // information about that particular peer. See peer_info. + // Query information about connected peers for this torrent. If the + // torrent_handle is invalid, it will throw a system_error exception. + // + // ``post_peer_info()`` is asynchronous and will trigger the posting of + // a peer_info_alert. The alert contain a list of peer_info objects, one + // for each connected peer. + // + // ``get_peer_info()`` is synchronous and takes a reference to a vector + // that will be cleared and filled with one entry for each peer + // connected to this torrent, given the handle is valid. Each entry in + // the vector contains information about that particular peer. See + // peer_info. + void post_peer_info() const; void get_peer_info(std::vector& v) const; // calculates ``distributed_copies``, ``distributed_full_copies`` and @@ -361,14 +371,27 @@ namespace aux { // you're not interested in it (and see performance issues), you can // filter them out. // + // The ``status()`` function will block until the internal libtorrent + // thread responds with the torrent_status object. To avoid blocking, + // instead call ``post_status()``. It will trigger posting of a + // state_update_alert with a single torrent_status object for this + // torrent. + // + // In order to get regular updates for torrents whose status changes, + // consider calling session::post_torrent_updates()`` instead. + // // By default everything is included. The flags you can use to decide // what to *include* are defined in this class. torrent_status status(status_flags_t flags = status_flags_t::all()) const; - - // ``get_download_queue()`` returns a vector with information about pieces - // that are partially downloaded or not downloaded but partially - // requested. See partial_piece_info for the fields in the returned - // vector. + void post_status(status_flags_t flags = status_flags_t::all()) const; + + // ``post_download_queue()`` triggers a download_queue_alert to be + // posted. + // ``get_download_queue()`` is a synchronous call and returns a vector + // with information about pieces that are partially downloaded or not + // downloaded but partially requested. See partial_piece_info for the + // fields in the returned vector. + void post_download_queue() const; std::vector get_download_queue() const; void get_download_queue(std::vector& queue) const; @@ -468,6 +491,7 @@ namespace aux { // already keeps track of this internally and no calculation is required. void file_progress(std::vector& progress, file_progress_flags_t flags = {}) const; std::vector file_progress(file_progress_flags_t flags = {}) const; + void post_file_progress(file_progress_flags_t flags) const; // This function returns a vector with status about files // that are open for this torrent. Any file that is not open @@ -482,7 +506,7 @@ namespace aux { // non-empty), this will clear the error and start the torrent again. void clear_error() const; - // ``trackers()`` will return the list of trackers for this torrent. The + // ``trackers()`` returns the list of trackers for this torrent. The // announce entry contains both a string ``url`` which specify the // announce url for the tracker as well as an int ``tier``, which is // specifies the order in which this tracker is tried. If you want @@ -492,6 +516,9 @@ namespace aux { // immediate effect, you have to call force_reannounce(). See // announce_entry. // + // ``post_trackers()`` is the asynchronous version of ``trackers()``. It + // will trigger a tracker_list_alert to be posted. + // // ``add_tracker()`` will look if the specified tracker is already in the // set. If it is, it doesn't do anything. If it's not in the current set // of trackers, it will insert it in the tier specified in the @@ -503,6 +530,7 @@ namespace aux { std::vector trackers() const; void replace_trackers(std::vector const&) const; void add_tracker(announce_entry const&) const; + void post_trackers() const; // TODO: 3 unify url_seed and http_seed with just web_seed, using the // web_seed_entry. @@ -648,18 +676,57 @@ namespace aux { static constexpr resume_data_flags_t flush_disk_cache = 0_bit; // the resume data will contain the metadata from the torrent file as - // well. This is default for any torrent that's added without a - // torrent file (such as a magnet link or a URL). + // well. This is useful for clients that don't keep .torrent files + // around separately, or for torrents that were added via a magnet link. static constexpr resume_data_flags_t save_info_dict = 1_bit; - // if nothing significant has changed in the torrent since the last - // time resume data was saved, fail this attempt. Significant changes - // primarily include more data having been downloaded, file or piece - // priorities having changed etc. If the resume data doesn't need - // saving, a save_resume_data_failed_alert is posted with the error - // resume_data_not_modified. + // this flag has the same behavior as the combination of: + // if_counters_changed | if_download_progress | if_config_changed | + // if_state_changed | if_metadata_changed static constexpr resume_data_flags_t only_if_modified = 2_bit; + // save resume data if any counters has changed since the last time + // resume data was saved. This includes upload/download counters, active + // time counters and scrape data. A torrent that is not paused will have + // its active time counters incremented continuously. + static constexpr resume_data_flags_t if_counters_changed = 3_bit; + + // save the resume data if any blocks have been downloaded since the + // last time resume data was saved. This includes: + // * checking existing files on disk + // * downloading a block from a peer + static constexpr resume_data_flags_t if_download_progress = 4_bit; + + // save the resume data if configuration options changed since last time + // the resume data was saved. This includes: + // * file- or piece priorities + // * upload- and download rate limits + // * change max-uploads (unchoke slots) + // * change max connection limit + // * enable/disable peer-exchange, local service discovery or DHT + // * enable/disable apply IP-filter + // * enable/disable auto-managed + // * enable/disable share-mode + // * enable/disable sequential-mode + // * files renamed + // * storage moved (save_path changed) + static constexpr resume_data_flags_t if_config_changed = 5_bit; + + // save the resume data if torrent state has changed since last time the + // resume data was saved. This includes: + // * upload mode + // * paused state + // * super-seeding + // * seed-mode + static constexpr resume_data_flags_t if_state_changed = 6_bit; + + // save the resume data if any *metadata* changed since the last time + // resume data was saved. This includes: + // * add/remove web seeds + // * add/remove trackers + // * receiving metadata for a magnet link + static constexpr resume_data_flags_t if_metadata_changed = 7_bit; + // ``save_resume_data()`` asks libtorrent to generate fast-resume data for // this torrent. The fast resume data (stored in an add_torrent_params // object) can be used to resume a torrent in the next session without @@ -758,11 +825,16 @@ namespace aux { // the initial loop, and thwart the counter otherwise. void save_resume_data(resume_data_flags_t flags = {}) const; - // This function returns true if any whole chunk has been downloaded - // since the torrent was first loaded or since the last time the resume - // data was saved. When saving resume data periodically, it makes sense - // to skip any torrent which hasn't downloaded anything since the last - // time. + // This function returns true if anything that is stored in the resume + // data has changed since the last time resume data was saved. + // The overload that takes ``flags`` let you ask if specific categories + // of properties have changed. These flags have the same behavior as in + // the save_resume_data() call. + // + // This is a *blocking* call. It will wait for a response from + // libtorrent's main thread. A way to avoid blocking is to instead + // call save_resume_data() directly, specifying the conditions under + // which resume data should be saved. // //.. note:: // A torrent's resume data is considered saved as soon as the @@ -770,6 +842,7 @@ namespace aux { // alert is received and handled in order for this function to be // meaningful. bool need_save_resume_data() const; + bool need_save_resume_data(resume_data_flags_t flags) const; // Every torrent that is added is assigned a queue position exactly one // greater than the greatest queue position of all existing torrents. @@ -968,14 +1041,18 @@ namespace aux { // ================ end deprecation ============ #endif - // Fills the specified ``std::vector`` with the availability for - // each piece in this torrent. libtorrent does not keep track of - // availability for seeds, so if the torrent is seeding the availability - // for all pieces is reported as 0. - // // The piece availability is the number of peers that we are connected // that has advertised having a particular piece. This is the information // that libtorrent uses in order to prefer picking rare pieces. + // + // ``post_piece_availability()`` will trigger a piece_availability_alert + // to be posted. + // + // ``piece_availability()`` fills the specified ``std::vector`` + // with the availability for each piece in this torrent. libtorrent does + // not keep track of availability for seeds, so if the torrent is + // seeding the availability for all pieces is reported as 0. + void post_piece_availability() const; void piece_availability(std::vector& avail) const; // These functions are used to set and get the priority of individual diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_info.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_info.hpp index 91f02685..ff6faccb 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_info.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_info.hpp @@ -61,6 +61,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/aux_/vector.hpp" #include "libtorrent/announce_entry.hpp" +#include "libtorrent/index_range.hpp" #include "libtorrent/aux_/merkle_tree.hpp" namespace libtorrent { @@ -73,6 +74,13 @@ namespace aux { TORRENT_EXTRA_EXPORT void sanitize_append_path_element(std::string& path , string_view element); TORRENT_EXTRA_EXPORT bool verify_encoding(std::string& target); + + struct internal_drained_state + { + aux::vector urls; + std::vector web_seeds; + std::vector> nodes; + }; } // the web_seed_entry holds information about a web seed (also known @@ -341,7 +349,9 @@ TORRENT_VERSION_NAMESPACE_3 void set_web_seeds(std::vector seeds); // internal - void clear_web_seeds() { m_web_seeds.clear(); } + aux::internal_drained_state _internal_drain() { + return aux::internal_drained_state{std::move(m_urls), std::move(m_web_seeds), std::move(m_nodes)}; + } // ``total_size()`` returns the total number of bytes the torrent-file // represents. Note that this is the number of pieces times the piece @@ -360,6 +370,10 @@ TORRENT_VERSION_NAMESPACE_3 int piece_length() const { return m_files.piece_length(); } int num_pieces() const { return m_files.num_pieces(); } + // returns the number of blocks there are in the typical piece. There + // may be fewer in the last piece) + int blocks_per_piece() const { return m_files.blocks_per_piece(); } + // ``last_piece()`` returns the index to the last piece in the torrent and // ``end_piece()`` returns the index to the one-past-end piece in the // torrent diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_peer.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_peer.hpp index 9c2530fe..6e2c19a3 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/torrent_peer.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/torrent_peer.hpp @@ -249,39 +249,64 @@ namespace libtorrent { const address_v6::bytes_type addr; }; + // if we have i2p peer addresses, sort them *after* all IP addresses struct peer_address_compare { bool operator()(torrent_peer const* lhs, address const& rhs) const { +#if TORRENT_USE_I2P + if (lhs->is_i2p_addr) return false; +#endif return lhs->address() < rhs; } bool operator()(address const& lhs, torrent_peer const* rhs) const { +#if TORRENT_USE_I2P + if (rhs->is_i2p_addr) return true; +#endif return lhs < rhs->address(); } #if TORRENT_USE_I2P bool operator()(torrent_peer const* lhs, string_view rhs) const { - return lhs->dest().compare(rhs) < 0; + if (!lhs->is_i2p_addr) return true; + return lhs->dest() < rhs; } bool operator()(string_view lhs, torrent_peer const* rhs) const { - return lhs.compare(rhs->dest()) < 0; + if (!rhs->is_i2p_addr) return false; + return lhs < rhs->dest(); } #endif bool operator()(torrent_peer const* lhs, torrent_peer const* rhs) const { #if TORRENT_USE_I2P - if (rhs->is_i2p_addr == lhs->is_i2p_addr) - return lhs->dest().compare(rhs->dest()) < 0; + if (lhs->is_i2p_addr != rhs->is_i2p_addr) + return lhs->is_i2p_addr < rhs->is_i2p_addr; + + if (lhs->is_i2p_addr) + return lhs->dest() < rhs->dest(); #endif return lhs->address() < rhs->address(); } }; + + inline bool torrent_peer_equal(torrent_peer const* lhs, torrent_peer const* rhs) + { +#if TORRENT_USE_I2P + if (lhs->is_i2p_addr != rhs->is_i2p_addr) + return false; + + if (lhs->is_i2p_addr) + return lhs->dest() == rhs->dest(); +#endif + return lhs->address() == rhs->address() + && lhs->port == rhs->port; + } } #endif diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/tracker_manager.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/tracker_manager.hpp index 54fa4c64..4f9857af 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/tracker_manager.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/tracker_manager.hpp @@ -165,6 +165,9 @@ enum class event_t : std::uint8_t std::vector peers; std::vector peers4; std::vector peers6; +#if TORRENT_USE_I2P + std::vector i2p_peers; +#endif // our external IP address (if the tracker responded with ti, otherwise // INADDR_ANY) address external_ip; diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/version.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/version.hpp index 8ba01900..cc136f58 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/version.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/version.hpp @@ -39,27 +39,27 @@ POSSIBILITY OF SUCH DAMAGE. #define LIBTORRENT_VERSION_MAJOR 2 #define LIBTORRENT_VERSION_MINOR 0 -#define LIBTORRENT_VERSION_TINY 8 +#define LIBTORRENT_VERSION_TINY 9 // 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 "2.0.8.0" -#define LIBTORRENT_REVISION "63e1ec8c8" +#define LIBTORRENT_VERSION "2.0.9.0" +#define LIBTORRENT_REVISION "559e52ca3" namespace libtorrent { // the major, minor and tiny versions of libtorrent constexpr int version_major = 2; constexpr int version_minor = 0; - constexpr int version_tiny = 8; + constexpr int version_tiny = 9; // the libtorrent version in string form - constexpr char const* version_str = "2.0.8.0"; + constexpr char const* version_str = "2.0.9.0"; // the git commit of this libtorrent version - constexpr std::uint64_t version_revision = 0x63e1ec8c8; + constexpr std::uint64_t version_revision = 0x559e52ca3; // returns the libtorrent version as string form in this format: // "..." diff --git a/3rd/libtorrent-rasterbar/include/libtorrent/web_peer_connection.hpp b/3rd/libtorrent-rasterbar/include/libtorrent/web_peer_connection.hpp index b6973ff1..f319a52d 100644 --- a/3rd/libtorrent-rasterbar/include/libtorrent/web_peer_connection.hpp +++ b/3rd/libtorrent-rasterbar/include/libtorrent/web_peer_connection.hpp @@ -89,6 +89,7 @@ namespace libtorrent { void handle_redirect(int bytes_left); void handle_error(int bytes_left); void maybe_harvest_piece(); + void disable(error_code const& ec); // returns the block currently being // downloaded. And the progress of that diff --git a/3rd/libtorrent-rasterbar/simulation/Jamfile b/3rd/libtorrent-rasterbar/simulation/Jamfile index 0dd3e1da..479664cc 100644 --- a/3rd/libtorrent-rasterbar/simulation/Jamfile +++ b/3rd/libtorrent-rasterbar/simulation/Jamfile @@ -35,7 +35,9 @@ run test_socks5.cpp ; run test_checking.cpp ; run test_optimistic_unchoke.cpp ; run test_transfer.cpp ; -run test_transfer_matrix.cpp ; +run test_transfer_no_files.cpp ; +run test_transfer_full_invalid_files.cpp ; +run test_transfer_partial_valid_files.cpp ; run test_http_connection.cpp ; run test_web_seed.cpp ; run test_auto_manage.cpp ; diff --git a/3rd/libtorrent-rasterbar/simulation/disk_io.cpp b/3rd/libtorrent-rasterbar/simulation/disk_io.cpp index 31ea409b..86bb6300 100644 --- a/3rd/libtorrent-rasterbar/simulation/disk_io.cpp +++ b/3rd/libtorrent-rasterbar/simulation/disk_io.cpp @@ -154,18 +154,24 @@ lt::sha256_hash generate_block_hash(lt::piece_index_t p, int const offset) return ret.final(); } -void generate_block(char* b, lt::peer_request const& r, int const pad_bytes) +void generate_block(char* b, lt::peer_request r, int const pad_bytes, int const piece_size) { - auto const fill = generate_block_fill(r.piece, (r.start / lt::default_block_size)); - // for now we don't support unaligned start address - TORRENT_ASSERT((r.start % fill.size()) == 0); char* end = b + r.length - pad_bytes; while (b < end) { - int const bytes = std::min(int(fill.size()), int(end - b)); - std::memcpy(b, fill.data(), bytes); + auto const fill = generate_block_fill(r.piece, (r.start / lt::default_block_size)); + + int const block_offset = r.start % int(fill.size()); + int const bytes = std::min(std::min(int(fill.size() - block_offset), int(end - b)), piece_size - r.start); + std::memcpy(b, fill.data() + block_offset, bytes); b += bytes; + r.start += bytes; + if (r.start >= piece_size) + { + r.start = 0; + ++r.piece; + } } if (pad_bytes > 0) @@ -329,11 +335,9 @@ struct test_disk_io final : lt::disk_interface TORRENT_ASSERT(static_cast(idx) == 0); TORRENT_ASSERT(m_files != nullptr); - queue_event(lt::microseconds(1), [this] () mutable { - m_files = nullptr; - m_blocks_per_piece = 0; - m_have.clear(); - }); + m_files = nullptr; + m_blocks_per_piece = 0; + m_have.clear(); } void abort(bool) override {} @@ -360,7 +364,9 @@ struct test_disk_io final : lt::disk_interface if (m_state.corrupt_data_in-- <= 0) lt::aux::random_bytes(buf); else - generate_block(buf.data(), r, pads_in_req(m_pad_bytes, r, m_files->piece_size(r.piece))); + generate_block(buf.data(), r + , pads_in_req(m_pad_bytes, r, m_files->piece_size(r.piece)) + , m_files->piece_size(r.piece)); } post(m_ioc, [h=std::move(h), b=std::move(buf)] () mutable { h(std::move(b), lt::storage_error{}); }); @@ -535,6 +541,9 @@ struct test_disk_io final : lt::disk_interface else if (m_state.files == existing_files_mode::no_files) ret = lt::status_t::no_error; + if (p && lt::aux::contains_resume_data(*p)) + ret = lt::status_t::no_error; + queue_event(lt::microseconds(1), [this,ret,h=std::move(handler)] () mutable { post(m_ioc, [ret,h=std::move(h)] { h(ret, lt::storage_error()); }); }); diff --git a/3rd/libtorrent-rasterbar/simulation/disk_io.hpp b/3rd/libtorrent-rasterbar/simulation/disk_io.hpp index fe3a89a9..4e4911eb 100644 --- a/3rd/libtorrent-rasterbar/simulation/disk_io.hpp +++ b/3rd/libtorrent-rasterbar/simulation/disk_io.hpp @@ -49,7 +49,7 @@ lt::sha1_hash generate_hash1(lt::piece_index_t const p, lt::file_storage const& lt::sha1_hash generate_hash2(lt::piece_index_t p, lt::file_storage const& fs , lt::span const hashes); lt::sha256_hash generate_block_hash(lt::piece_index_t p, int offset); -void generate_block(char* b, lt::peer_request const& r); +void generate_block(char* b, lt::peer_request r, int pad_bytes, int piece_size); std::shared_ptr create_test_torrent(int piece_size , int num_pieces, lt::create_flags_t flags, int num_files = 1); lt::add_torrent_params create_test_torrent( diff --git a/3rd/libtorrent-rasterbar/simulation/libsimulator/include/simulator/simulator.hpp b/3rd/libtorrent-rasterbar/simulation/libsimulator/include/simulator/simulator.hpp index 2791b461..5d64c11f 100644 --- a/3rd/libtorrent-rasterbar/simulation/libsimulator/include/simulator/simulator.hpp +++ b/3rd/libtorrent-rasterbar/simulation/libsimulator/include/simulator/simulator.hpp @@ -1041,7 +1041,7 @@ namespace sim , boost::system::error_code& ec); void unbind_socket(asio::ip::tcp::socket* socket , asio::ip::tcp::endpoint const& ep); - void rebind_socket(asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep); + void rebind_socket(asio::ip::tcp::socket* prev, asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep); asio::ip::udp::endpoint bind_udp_socket(asio::ip::udp::socket* socket , asio::ip::udp::endpoint ep @@ -1166,7 +1166,7 @@ namespace sim , boost::system::error_code& ec); void unbind_socket(ip::tcp::socket* socket , ip::tcp::endpoint const& ep); - void rebind_socket(asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep); + void rebind_socket(asio::ip::tcp::socket* prev, asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep); ip::udp::endpoint bind_udp_socket(ip::udp::socket* socket, ip::udp::endpoint ep , boost::system::error_code& ec); diff --git a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/io_service.cpp b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/io_service.cpp index 873790ad..b48d7a57 100644 --- a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/io_service.cpp +++ b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/io_service.cpp @@ -180,9 +180,9 @@ namespace sim { namespace asio { m_sim.unbind_socket(socket, ep); } - void io_context::rebind_socket(asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep) + void io_context::rebind_socket(asio::ip::tcp::socket* prev, asio::ip::tcp::socket* s, asio::ip::tcp::endpoint ep) { - m_sim.rebind_socket(s, ep); + m_sim.rebind_socket(prev, s, ep); } ip::udp::endpoint io_context::bind_udp_socket(ip::udp::socket* socket diff --git a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/simulation.cpp b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/simulation.cpp index f6cf340e..3a3b47a9 100644 --- a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/simulation.cpp +++ b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/simulation.cpp @@ -23,6 +23,7 @@ All rights reserved. #include // for tie #include // for make_shared #include // for printf +#include using namespace sim::asio; @@ -130,10 +131,11 @@ namespace sim m_timer_queue.erase(begin); } - void simulation::rebind_socket(ip::tcp::socket* s, ip::tcp::endpoint ep) + void simulation::rebind_socket(ip::tcp::socket* prev, ip::tcp::socket* s, ip::tcp::endpoint ep) { auto i = m_listen_sockets.find(ep); assert(i != m_listen_sockets.end()); + if (i->second != prev) return; i->second = s; } diff --git a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/tcp_socket.cpp b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/tcp_socket.cpp index c0ca419a..302fdcf6 100644 --- a/3rd/libtorrent-rasterbar/simulation/libsimulator/src/tcp_socket.cpp +++ b/3rd/libtorrent-rasterbar/simulation/libsimulator/src/tcp_socket.cpp @@ -78,7 +78,7 @@ namespace ip { s.m_bound_to = ip::tcp::endpoint(); if (m_bound_to != ip::tcp::endpoint()) - m_io_service.rebind_socket(this, m_bound_to); + m_io_service.rebind_socket(&s, this, m_bound_to); } tcp::socket::~socket() diff --git a/3rd/libtorrent-rasterbar/simulation/test_tracker.cpp b/3rd/libtorrent-rasterbar/simulation/test_tracker.cpp index 6d645b90..6dabfbc3 100644 --- a/3rd/libtorrent-rasterbar/simulation/test_tracker.cpp +++ b/3rd/libtorrent-rasterbar/simulation/test_tracker.cpp @@ -47,6 +47,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/torrent_info.hpp" #include "libtorrent/aux_/ip_helpers.hpp" // for is_v4 +#include #include using namespace lt; @@ -1560,11 +1561,11 @@ struct tracker_ent int tier; }; -template void test_tracker_tiers(lt::settings_pack pack , std::vector
        local_addresses , std::vector trackers - , TestFun test) + , std::function test + , boost::optional> test2 = boost::none) { using namespace libtorrent; @@ -1610,23 +1611,32 @@ void test_tracker_tiers(lt::settings_pack pack sim::asio::io_context tracker4(sim, addr("3.0.0.4")); sim::asio::io_context tracker5(sim, addr("f8e0::1")); sim::asio::io_context tracker6(sim, addr("f8e0::2")); + sim::asio::io_context tracker7(sim, addr("3.0.0.5")); sim::http_server http1(tracker1, 8080); sim::http_server http2(tracker2, 8080); sim::http_server http3(tracker3, 8080); sim::http_server http4(tracker4, 8080); sim::http_server http5(tracker5, 8080); sim::http_server http6(tracker6, 8080); + sim::http_server http7(tracker7, 8080); - int received_announce[6] = {0, 0, 0, 0, 0, 0}; + int received_announce[7] = {0, 0, 0, 0, 0, 0, 0}; auto const return_no_peers = [&](std::string method, std::string req , std::map&, int const tracker_index) { ++received_announce[tracker_index]; - std::string const ret = "d8:intervali60e5:peers0:e"; + std::string const ret = "d8:intervali1800e5:peers0:e"; return sim::send_response(200, "OK", static_cast(ret.size())) + ret; }; + auto const return_404 = [&](std::string method, std::string req + , std::map&, int const tracker_index) + { + ++received_announce[tracker_index]; + return sim::send_response(404, "Not Found", 0); + }; + using namespace std::placeholders; http1.register_handler("/announce", std::bind(return_no_peers, _1, _2, _3, 0)); http2.register_handler("/announce", std::bind(return_no_peers, _1, _2, _3, 1)); @@ -1634,6 +1644,7 @@ void test_tracker_tiers(lt::settings_pack pack http4.register_handler("/announce", std::bind(return_no_peers, _1, _2, _3, 3)); http5.register_handler("/announce", std::bind(return_no_peers, _1, _2, _3, 4)); http6.register_handler("/announce", std::bind(return_no_peers, _1, _2, _3, 5)); + http7.register_handler("/announce", std::bind(return_404, _1, _2, _3, 6)); lt::session_proxy zombie; @@ -1641,10 +1652,8 @@ void test_tracker_tiers(lt::settings_pack pack pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:6881,[::]:6881"); auto ses = std::make_shared(pack, ios0); - // only monitor alerts for session 0 (the downloader) print_alerts(*ses); - // the first peer is a downloader, the second peer is a seed lt::add_torrent_params params = ::create_torrent(1); params.flags &= ~lt::torrent_flags::auto_managed; params.flags &= ~lt::torrent_flags::paused; @@ -1655,16 +1664,36 @@ void test_tracker_tiers(lt::settings_pack pack params.save_path = save_path(0); ses->async_add_torrent(params); - sim::timer t(sim, lt::seconds(30), [&](boost::system::error_code const&) { test(received_announce); - - zombie = ses->abort(); - ses.reset(); + if (test2) + { + std::memset(&received_announce, 0, sizeof(received_announce)); + } + else + { + zombie = ses->abort(); + ses.reset(); + } }); - sim.run(); + if (test2) + { + sim::timer t2(sim, lt::minutes(31), [&](boost::system::error_code const&) + { + (*test2)(received_announce); + + zombie = ses->abort(); + ses.reset(); + }); + sim.run(); + } + else + { + sim.run(); + } + } bool one_of(int a, int b) @@ -1681,12 +1710,13 @@ TORRENT_TEST(tracker_tiers_multi_homed) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_CHECK(one_of(a[0], a[1])); TEST_EQUAL(a[2], 0); TEST_EQUAL(a[3], 0); TEST_EQUAL(a[4], 0); TEST_EQUAL(a[5], 0); + TEST_EQUAL(a[6], 0); }); } @@ -1697,13 +1727,14 @@ TORRENT_TEST(tracker_tiers_all_trackers_multi_homed) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 2); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); TEST_EQUAL(a[3], 0); TEST_EQUAL(a[4], 0); TEST_EQUAL(a[5], 0); + TEST_EQUAL(a[6], 0); }); } @@ -1714,11 +1745,12 @@ TORRENT_TEST(tracker_tiers_all_tiers_multi_homed) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_CHECK(one_of(a[0], a[1])); TEST_CHECK(one_of(a[2], a[3])); TEST_EQUAL(a[4], 0); TEST_EQUAL(a[5], 0); + TEST_EQUAL(a[6], 0); }); } TORRENT_TEST(tracker_tiers_all_trackers_and_tiers_multi_homed) @@ -1728,7 +1760,7 @@ TORRENT_TEST(tracker_tiers_all_trackers_and_tiers_multi_homed) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 2); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 2); @@ -1745,7 +1777,7 @@ TORRENT_TEST(tracker_tiers) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_CHECK(one_of(a[0], a[1])); TEST_EQUAL(a[2], 0); TEST_EQUAL(a[3], 0); @@ -1761,7 +1793,7 @@ TORRENT_TEST(tracker_tiers_all_trackers) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 2); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1778,7 +1810,7 @@ TORRENT_TEST(tracker_tiers_all_tiers) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_CHECK(one_of(a[0], a[1])); TEST_CHECK(one_of(a[2], a[3])); TEST_EQUAL(a[4], 0); @@ -1793,7 +1825,7 @@ TORRENT_TEST(tracker_tiers_all_trackers_and_tiers) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1") } , { {"3.0.0.1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 2); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 2); @@ -1812,7 +1844,7 @@ TORRENT_TEST(tracker_tiers_unreachable_tracker) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1") } , { {"f8e0::1", 0}, {"3.0.0.2", 0}, {"3.0.0.3", 1}, {"3.0.0.4", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1833,7 +1865,7 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_same_tier) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"ipv6-only-tracker.com", 0}, {"dual-tracker.com", 0}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1850,7 +1882,7 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_different_tiers) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"ipv6-only-tracker.com", 0}, {"dual-tracker.com", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1870,7 +1902,7 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_all_trackers) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"ipv6-only-tracker.com", 0}, {"dual-tracker.com", 0}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1887,7 +1919,7 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_different_tiers_all_trackers) pack.set_bool(settings_pack::announce_to_all_trackers, true); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"ipv6-only-tracker.com", 0}, {"dual-tracker.com", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1904,7 +1936,7 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_different_tiers_all_tiers) pack.set_bool(settings_pack::announce_to_all_trackers, false); test_tracker_tiers(pack, { addr("50.0.0.1"), addr("f8e0::10") } , { {"ipv6-only-tracker.com", 0}, {"dual-tracker.com", 1}} - , [](int (&a)[6]) { + , [](int (&a)[7]) { TEST_EQUAL(a[0], 0); TEST_EQUAL(a[1], 2); TEST_EQUAL(a[2], 0); @@ -1914,6 +1946,84 @@ TORRENT_TEST(tracker_tiers_v4_and_v6_different_tiers_all_tiers) }); } +TORRENT_TEST(tracker_tiers_retry_all) +{ + settings_pack pack = settings(); + pack.set_bool(settings_pack::announce_to_all_tiers, true); + pack.set_bool(settings_pack::announce_to_all_trackers, true); + // the torrent is a hybrid torrent, so it will announce twice, once for v1 + // and once for v2 + test_tracker_tiers(pack, { addr("50.0.0.1") } + , { {"3.0.0.1", 0}, {"3.0.0.5", 1}} + , [](int (&a)[7]) { + TEST_EQUAL(a[0], 2); + TEST_EQUAL(a[1], 0); + TEST_EQUAL(a[2], 0); + TEST_EQUAL(a[3], 0); + TEST_EQUAL(a[4], 0); + TEST_EQUAL(a[5], 0); + // the failing tracker is retried 17 seconds later + TEST_EQUAL(a[6], 4); + }, std::function([](int (&a)[7]) { + // this is 31 minutes later + // the working tracker is re-announced once, since interval is 1800 + TEST_EQUAL(a[0], 2); + TEST_EQUAL(a[1], 0); + TEST_EQUAL(a[2], 0); + TEST_EQUAL(a[3], 0); + TEST_EQUAL(a[4], 0); + TEST_EQUAL(a[5], 0); + // The failing tracker is retried after: + // 72 seconds + // 189 seconds + // 396 seconds + // 711 seconds + // 1166 seconds + // 1783 seconds + // 6 * 2 = 12 + TEST_EQUAL(a[6], 12); + })); +} + +TORRENT_TEST(tracker_tiers_retry_all_multiple_trackers_per_tier) +{ + settings_pack pack = settings(); + pack.set_bool(settings_pack::announce_to_all_tiers, true); + pack.set_bool(settings_pack::announce_to_all_trackers, true); + // the torrent is a hybrid torrent, so it will announce twice, once for v1 + // and once for v2 + test_tracker_tiers(pack, { addr("50.0.0.1") } + , { {"3.0.0.1", 0}, {"3.0.0.5", 1}, {"3.0.0.2", 1}} + , [](int (&a)[7]) { + TEST_EQUAL(a[0], 2); + TEST_EQUAL(a[1], 2); + TEST_EQUAL(a[2], 0); + TEST_EQUAL(a[3], 0); + TEST_EQUAL(a[4], 0); + TEST_EQUAL(a[5], 0); + // the failing tracker is retried 17 seconds later + TEST_EQUAL(a[6], 4); + }, std::function([](int (&a)[7]) { + // this is 31 minutes later + // the working tracker is re-announced once, since interval is 1800 + TEST_EQUAL(a[0], 2); + TEST_EQUAL(a[1], 2); + TEST_EQUAL(a[2], 0); + TEST_EQUAL(a[3], 0); + TEST_EQUAL(a[4], 0); + TEST_EQUAL(a[5], 0); + // The failing tracker is retried after: + // 72 seconds + // 189 seconds + // 396 seconds + // 711 seconds + // 1166 seconds + // 1783 seconds + // 6 * 2 = 12 + TEST_EQUAL(a[6], 12); + })); +} + // TODO: test external IP // TODO: test with different queuing settings // TODO: test when a torrent transitions from downloading to finished and diff --git a/3rd/libtorrent-rasterbar/simulation/test_transfer_full_invalid_files.cpp b/3rd/libtorrent-rasterbar/simulation/test_transfer_full_invalid_files.cpp new file mode 100644 index 00000000..b038059b --- /dev/null +++ b/3rd/libtorrent-rasterbar/simulation/test_transfer_full_invalid_files.cpp @@ -0,0 +1,43 @@ +/* + +Copyright (c) 2021, 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 "transfer_sim.hpp" + +TORRENT_TEST(transfer_matrix) +{ + using fm = existing_files_mode; + + run_all_combinations([] (test_transfer_flags_t const flags) { + return run_matrix_test(flags, fm::full_invalid); + }); +} + diff --git a/3rd/libtorrent-rasterbar/simulation/test_transfer_matrix.cpp b/3rd/libtorrent-rasterbar/simulation/test_transfer_matrix.cpp deleted file mode 100644 index 8f393a3d..00000000 --- a/3rd/libtorrent-rasterbar/simulation/test_transfer_matrix.cpp +++ /dev/null @@ -1,97 +0,0 @@ -/* - -Copyright (c) 2021, 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 "transfer_sim.hpp" - -void run_matrix_test(test_transfer_flags_t const flags, existing_files_mode const files, bool const corruption) -{ - std::cout << "\n\nTEST CASE: " - << ((flags & tx::small_pieces) ? "small-pieces" : (flags & tx::large_pieces) ? "large-pieces" : "normal-pieces") - << "-" << (corruption ? "corruption" : "valid") - << "-" << ((flags & tx::v2_only) ? "v2_only" : (flags & tx::v1_only) ? "v1_only" : "hybrid") - << "-" << ((flags & tx::magnet_download) ? "magnet" : "torrent") - << "-" << ((flags & tx::multiple_files) ? "multi_file" : "single_file") - << "-" << files - << "\n\n"; - - auto downloader_disk = test_disk().set_files(files); - auto seeder_disk = test_disk(); - if (corruption) seeder_disk = seeder_disk.send_corrupt_data(num_pieces(flags) / 4 * blocks_per_piece(flags)); - std::set passed; - run_test(no_init - , record_finished_pieces(passed) - , expect_seed(!corruption) - , flags - , downloader_disk - , seeder_disk - ); - - int const expected_pieces = num_pieces(flags); - - // we we send some corrupt pieces, it's not straight-forward to predict - // exactly how many will pass the hash check, since a failure will cause - // a re-request and also a request of the block hashes (for v2 torrents) - if (corruption) - { - TEST_CHECK(int(passed.size()) < expected_pieces); - } - else - { - TEST_EQUAL(int(passed.size()), expected_pieces); - } -} - -TORRENT_TEST(transfer_matrix) -{ - using fm = existing_files_mode; - - for (test_transfer_flags_t piece_size : {test_transfer_flags_t{}, tx::small_pieces, tx::large_pieces}) - for (bool corruption : {false, true}) - for (test_transfer_flags_t bt_version : {test_transfer_flags_t{}, tx::v2_only, tx::v1_only}) - for (test_transfer_flags_t magnet : {test_transfer_flags_t{}, tx::magnet_download}) - for (test_transfer_flags_t multi_file : {test_transfer_flags_t{}, tx::multiple_files}) - for (fm files : {fm::no_files, fm::full_invalid, fm::partial_valid}) - { - // this will clear the history of all output we've printed so far. - // if we encounter an error from now on, we'll only print the relevant - // iteration - ::unit_test::reset_output(); - - // re-seed the random engine each iteration, to make the runs - // deterministic - lt::aux::random_engine().seed(0x23563a7f); - - run_matrix_test(piece_size | bt_version | magnet | multi_file, files, corruption); - if (::unit_test::g_test_failures > 0) return; - } -} - diff --git a/3rd/libtorrent-rasterbar/simulation/test_transfer_no_files.cpp b/3rd/libtorrent-rasterbar/simulation/test_transfer_no_files.cpp new file mode 100644 index 00000000..2be7ef7a --- /dev/null +++ b/3rd/libtorrent-rasterbar/simulation/test_transfer_no_files.cpp @@ -0,0 +1,43 @@ +/* + +Copyright (c) 2021, 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 "transfer_sim.hpp" + +TORRENT_TEST(transfer_matrix) +{ + using fm = existing_files_mode; + + run_all_combinations([] (test_transfer_flags_t const flags) { + return run_matrix_test(flags, fm::no_files); + }); +} + diff --git a/3rd/libtorrent-rasterbar/simulation/test_transfer_partial_valid_files.cpp b/3rd/libtorrent-rasterbar/simulation/test_transfer_partial_valid_files.cpp new file mode 100644 index 00000000..8bff09ac --- /dev/null +++ b/3rd/libtorrent-rasterbar/simulation/test_transfer_partial_valid_files.cpp @@ -0,0 +1,43 @@ +/* + +Copyright (c) 2021, 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 "transfer_sim.hpp" + +TORRENT_TEST(transfer_matrix) +{ + using fm = existing_files_mode; + + run_all_combinations([] (test_transfer_flags_t const flags) { + return run_matrix_test(flags, fm::partial_valid); + }); +} + diff --git a/3rd/libtorrent-rasterbar/simulation/test_utp.cpp b/3rd/libtorrent-rasterbar/simulation/test_utp.cpp index 28169558..5f991d0f 100644 --- a/3rd/libtorrent-rasterbar/simulation/test_utp.cpp +++ b/3rd/libtorrent-rasterbar/simulation/test_utp.cpp @@ -248,12 +248,12 @@ TORRENT_TEST(utp_small_kernel_send_buf) TEST_EQUAL(metric(cnt, "utp.utp_packet_resend"), 190); TEST_EQUAL(metric(cnt, "utp.utp_samples_above_target"), 0); - TEST_EQUAL(metric(cnt, "utp.utp_samples_below_target"), 786); + TEST_EQUAL(metric(cnt, "utp.utp_samples_below_target"), 785); - TEST_EQUAL(metric(cnt, "utp.utp_packets_in"), 795); + TEST_EQUAL(metric(cnt, "utp.utp_packets_in"), 793); TEST_EQUAL(metric(cnt, "utp.utp_payload_pkts_in"), 66); - TEST_EQUAL(metric(cnt, "utp.utp_packets_out"), 809); + TEST_EQUAL(metric(cnt, "utp.utp_packets_out"), 807); // we don't expect any invalid packets, since we're talking to ourself TEST_EQUAL(metric(cnt, "utp.utp_invalid_pkts_in"), 0); diff --git a/3rd/libtorrent-rasterbar/simulation/transfer_sim.cpp b/3rd/libtorrent-rasterbar/simulation/transfer_sim.cpp index 81489544..51275ca6 100644 --- a/3rd/libtorrent-rasterbar/simulation/transfer_sim.cpp +++ b/3rd/libtorrent-rasterbar/simulation/transfer_sim.cpp @@ -8,6 +8,8 @@ see LICENSE file. */ #include "libtorrent/settings_pack.hpp" +#include "libtorrent/write_resume_data.hpp" +#include "libtorrent/read_resume_data.hpp" #include "transfer_sim.hpp" @@ -25,6 +27,70 @@ void record_finished_pieces::operator()(lt::session&, lt::alert const* a) const m_passed->insert(pf->piece_index); } +template +void lengthen(Container& c) +{ + if (c.size() == 0) return; + c.resize(c.size() + 1); +} + +restore_from_resume::restore_from_resume() + : m_last_check() +{} + +void restore_from_resume::operator()(lt::session& ses, lt::alert const* a) +{ + if (m_done) return; + + if (auto* rd = lt::alert_cast(a)) + { + m_resume_buffer = lt::write_resume_data_buf(rd->params); + auto torrents = ses.get_torrents(); + ses.remove_torrent(torrents[0]); + return; + } + + if (lt::alert_cast(a)) + { + lt::add_torrent_params atp = lt::read_resume_data(m_resume_buffer); + m_resume_buffer.clear(); + + // make sure loading resume data tolerates oversized bitfields + lengthen(atp.have_pieces); + lengthen(atp.verified_pieces); + + for (auto& m : atp.merkle_tree_mask) + lengthen(m); + + for (auto& v : atp.verified_leaf_hashes) + lengthen(v); + + ses.async_add_torrent(atp); + m_done = true; + return; + } + + // we only want to do this once + if (m_triggered) + return; + + auto const now = lt::clock_type::now(); + if (now < m_last_check + lt::milliseconds(100)) + return; + + m_last_check = now; + auto torrents = ses.get_torrents(); + if (torrents.empty()) + return; + + auto h = torrents.front(); + if (h.status().num_pieces < 7) + return; + + h.save_resume_data(lt::torrent_handle::save_info_dict); + m_triggered = true; +} + expect_seed::expect_seed(bool e) : m_expect(e) {} void expect_seed::operator()(std::shared_ptr ses[2]) const { @@ -51,3 +117,86 @@ int num_pieces(test_transfer_flags_t const flags) } return 11; } + +bool run_matrix_test(test_transfer_flags_t const flags, existing_files_mode const files) +{ + // v2 (compatible) torrents require power-of-2 + // piece sizes + if ((flags & tx::odd_pieces) && !(flags & tx::v1_only)) + return false; + + // you can't download the metadata from a web + // seed, so we don't support web-seeding and + // magnet download + if ((flags & tx::web_seed) && (flags & tx::magnet_download)) + return false; + + // the web server in libsimulator only supports a single connection at a + // time. When disconnecting and re-connecting quickly, the initial + // connection is still held open, causing the second connection to fail. + // therefore, this test configuration does not work (yet). Perhaps the + // server could be changed to boot any existing connection when accepting a + // new one. + if ((flags & tx::web_seed) && (flags && tx::resume_restart)) + return false; + + // this will clear the history of all output we've printed so far. + // if we encounter an error from now on, we'll only print the relevant + // iteration + ::unit_test::reset_output(); + + // re-seed the random engine each iteration, to make the runs + // deterministic + lt::aux::random_engine().seed(0x23563a7f); + + std::cout << "\n\nTEST CASE: " + << ((flags & tx::small_pieces) ? "small_pieces" + : (flags & tx::large_pieces) ? "large_pieces" + : (flags & tx::odd_pieces) ? "odd_pieces" + : "normal_pieces") + << "-" << ((flags & tx::corruption) ? "corruption" : "valid") + << "-" << ((flags & tx::v2_only) ? "v2_only" : (flags & tx::v1_only) ? "v1_only" : "hybrid") + << "-" << ((flags & tx::magnet_download) ? "magnet" : "torrent") + << "-" << ((flags & tx::multiple_files) ? "multi_file" : "single_file") + << "-" << ((flags & tx::web_seed) ? "web_seed" : "bt_peers") + << "-" << ((flags & tx::resume_restart) ? "resume_restart" : "continuous") + << "-" << files + << "\n\n"; + + auto downloader_disk = test_disk().set_files(files); + auto seeder_disk = test_disk(); + if (flags & tx::corruption) + seeder_disk = seeder_disk.send_corrupt_data(num_pieces(flags) / 4 * blocks_per_piece(flags)); + std::set passed; + + combine_t handler; + handler.add(record_finished_pieces(passed)); + + if (flags & tx::resume_restart) + handler.add(restore_from_resume()); + + run_test(no_init + , handler + , expect_seed(!(flags & tx::corruption)) + , flags + , downloader_disk + , seeder_disk + ); + + int const expected_pieces = num_pieces(flags); + + // we we send some corrupt pieces, it's not straight-forward to predict + // exactly how many will pass the hash check, since a failure will cause + // a re-request and also a request of the block hashes (for v2 torrents) + if (flags & tx::corruption) + { + TEST_CHECK(int(passed.size()) < expected_pieces); + } + else + { + TEST_EQUAL(int(passed.size()), expected_pieces); + } + + return ::unit_test::g_test_failures > 0; +} + diff --git a/3rd/libtorrent-rasterbar/simulation/transfer_sim.hpp b/3rd/libtorrent-rasterbar/simulation/transfer_sim.hpp index 1abb9830..e5ad52b4 100644 --- a/3rd/libtorrent-rasterbar/simulation/transfer_sim.hpp +++ b/3rd/libtorrent-rasterbar/simulation/transfer_sim.hpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "simulator/simulator.hpp" #include "simulator/socks_server.hpp" #include "simulator/utils.hpp" +#include "simulator/http_server.hpp" #include "libtorrent/session.hpp" #include "libtorrent/address.hpp" @@ -48,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/ip_filter.hpp" #include "libtorrent/alert_types.hpp" #include "libtorrent/aux_/proxy_settings.hpp" +#include "libtorrent/aux_/escape_string.hpp" #include "libtorrent/settings_pack.hpp" #include "libtorrent/create_torrent.hpp" #include "libtorrent/random.hpp" @@ -115,7 +117,6 @@ void run_test( pack.set_int(settings_pack::allowed_enc_level, settings_pack::pe_plaintext); pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer0_ip[use_ipv6], use_ipv6, "6881")); - // create session std::shared_ptr ses[2]; @@ -125,6 +126,12 @@ void run_test( ses[0] = std::make_shared(params, ios0); pack.set_str(settings_pack::listen_interfaces, make_ep_string(peer1_ip[use_ipv6], use_ipv6, "6881")); + if (flags & tx::resume_restart) + { + // if we don't enable this, the second connection attempt will be + // rejected + pack.set_bool(settings_pack::allow_multiple_connections_per_ip, true); + } params.disk_io_constructor = seed_disk_constructor.set_files(existing_files_mode::full_valid); ses[1] = std::make_shared(params, ios1); @@ -132,30 +139,81 @@ void run_test( setup(*ses[0], *ses[1]); // only monitor alerts for session 0 (the downloader) - print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) { - if (auto ta = alert_cast(a)) + print_alerts(*ses[0], [&](lt::session& ses, lt::alert const* a) { + if (auto ta = lt::alert_cast(a)) { - if (flags & tx::connect_proxy) - ta->handle.connect_peer(lt::tcp::endpoint(proxy, 3000)); - else - ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); + if (!(flags & tx::web_seed)) + { + if (flags & tx::connect_proxy) + ta->handle.connect_peer(lt::tcp::endpoint(proxy, 3000)); + else + ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881)); + } } on_alert(ses, a); }, 0); print_alerts(*ses[1], [](lt::session&, lt::alert const*){}, 1); - lt::add_torrent_params atp = ::create_test_torrent(10 - , (flags & tx::v2_only) ? lt::create_torrent::v2_only + int const piece_size = (flags & tx::small_pieces) ? lt::default_block_size + : (flags & tx::large_pieces) ? (4 * lt::default_block_size) + : (flags & tx::odd_pieces) ? (2 * lt::default_block_size + 123) + : (2 * lt::default_block_size); + + int const num_pieces = 10; + + lt::create_flags_t const cflags + = ((flags & tx::v2_only) ? lt::create_torrent::v2_only : (flags & tx::v1_only) ? lt::create_torrent::v1_only - : lt::create_flags_t{} - , (flags & tx::small_pieces) ? 1 : (flags & tx::large_pieces) ? 4 : 2 - , (flags & tx::multiple_files) ? 3 : 1 - ); + : lt::create_flags_t{}) + | lt::create_torrent::allow_odd_piece_size; + + int const num_files = (flags & tx::multiple_files) ? 3 : 1; + + lt::add_torrent_params atp; + + atp.ti = ::create_test_torrent(piece_size, num_pieces, cflags, num_files); + // this is unused by the test disk I/O + atp.save_path = "."; atp.flags &= ~lt::torrent_flags::auto_managed; atp.flags &= ~lt::torrent_flags::paused; - ses[1]->async_add_torrent(atp); + sim::asio::io_context web_server(sim, lt::make_address_v4("2.2.2.2")); + sim::http_server http(web_server, 8080); + + int corrupt_counter = INT_MAX; + if (flags & tx::corruption) + corrupt_counter = lt::default_block_size * 2; + + if (flags & tx::web_seed) + { + auto const& fs = atp.ti->files(); + for (lt::file_index_t f : fs.file_range()) + { + std::string file_path = fs.file_path(f, "/"); + lt::convert_path_to_posix(file_path); + http.register_content(file_path, fs.file_size(f) + , [&fs,f,&corrupt_counter](std::int64_t offset, std::int64_t len) + { + TORRENT_ASSERT(offset + len <= fs.file_size(f)); + auto const req = fs.map_file(f, offset, len); + std::string ret; + ret.resize(req.length); + generate_block(&ret[0], req, 0, fs.piece_length()); + if (corrupt_counter < 0) + lt::aux::random_bytes(ret); + else if (corrupt_counter - len < 0) + lt::aux::random_bytes(lt::span(ret).subspan(corrupt_counter)); + corrupt_counter -= len; + return ret; + }); + } + } + + // if we're seeding with a web server, no need to start the second session + if (!(flags & tx::web_seed)) + ses[1]->async_add_torrent(atp); + auto torrent = atp.ti; atp.save_path = save_path(0); @@ -164,6 +222,9 @@ void run_test( atp.info_hashes = atp.ti->info_hashes(); atp.ti.reset(); } + if (flags & tx::web_seed) + atp.url_seeds.emplace_back("http://2.2.2.2:8080/"); + ses[0]->async_add_torrent(atp); sim::timer t(sim, timeout, [&](boost::system::error_code const&) @@ -200,16 +261,51 @@ void run_test( sim.run(); } +bool run_matrix_test(test_transfer_flags_t const flags, existing_files_mode const files); + void no_init(lt::session& ses0, lt::session& ses1); + +struct combine_t +{ + combine_t() {} + + void operator()(lt::session& s, lt::alert const* a) + { + for (auto& h : m_handlers) + h(s, a); + } + + void add(std::function h) + { + m_handlers.emplace_back(std::move(h)); + } + + std::vector> m_handlers; +}; + +// this alert handler records all pieces that complete and pass hash check into +// the set passed in to its constructor struct record_finished_pieces { record_finished_pieces(std::set& p); void operator()(lt::session&, lt::alert const* a) const; - std::set* m_passed; }; +// this alert handler will save resume data, remove the torrent and add it back +// resuming from the saved state +struct restore_from_resume +{ + restore_from_resume(); + void operator()(lt::session&, lt::alert const* a); + + lt::time_point m_last_check; + std::vector m_resume_buffer; + bool m_triggered = false; + bool m_done = false; +}; + struct expect_seed { expect_seed(bool e); @@ -220,4 +316,19 @@ struct expect_seed int blocks_per_piece(test_transfer_flags_t const flags); int num_pieces(test_transfer_flags_t const flags); +template +void run_all_combinations(F fun) +{ + for (test_transfer_flags_t piece_size : {test_transfer_flags_t{}, tx::odd_pieces, tx::small_pieces, tx::large_pieces}) + for (test_transfer_flags_t web_seed : {tx::web_seed, test_transfer_flags_t{}}) + for (test_transfer_flags_t corruption : {test_transfer_flags_t{}, tx::corruption}) + for (test_transfer_flags_t bt_version : {test_transfer_flags_t{}, tx::v2_only, tx::v1_only}) + for (test_transfer_flags_t magnet : {test_transfer_flags_t{}, tx::magnet_download}) + for (test_transfer_flags_t multi_file : {test_transfer_flags_t{}, tx::multiple_files}) + for (test_transfer_flags_t resume : {tx::resume_restart, test_transfer_flags_t{}}) + if (fun(piece_size | bt_version | magnet + | multi_file | web_seed | corruption | resume)) + return; +} + #endif diff --git a/3rd/libtorrent-rasterbar/simulation/utils.hpp b/3rd/libtorrent-rasterbar/simulation/utils.hpp index e99ccdf6..5e3cc348 100644 --- a/3rd/libtorrent-rasterbar/simulation/utils.hpp +++ b/3rd/libtorrent-rasterbar/simulation/utils.hpp @@ -87,6 +87,10 @@ constexpr test_transfer_flags_t small_pieces = 5_bit; constexpr test_transfer_flags_t large_pieces = 6_bit; constexpr test_transfer_flags_t multiple_files = 7_bit; constexpr test_transfer_flags_t connect_proxy = 8_bit; +constexpr test_transfer_flags_t odd_pieces = 9_bit; +constexpr test_transfer_flags_t web_seed = 10_bit; +constexpr test_transfer_flags_t corruption = 11_bit; +constexpr test_transfer_flags_t resume_restart = 12_bit; } void set_proxy(lt::session& ses, int proxy_type diff --git a/3rd/libtorrent-rasterbar/src/alert.cpp b/3rd/libtorrent-rasterbar/src/alert.cpp index f4fc7dd1..a848899e 100644 --- a/3rd/libtorrent-rasterbar/src/alert.cpp +++ b/3rd/libtorrent-rasterbar/src/alert.cpp @@ -58,6 +58,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hex.hpp" // to_hex #include "libtorrent/session_stats.hpp" #include "libtorrent/socket_type.hpp" +#include "libtorrent/peer_info.hpp" #include "libtorrent/aux_/ip_helpers.hpp" // for is_v4 #if TORRENT_ABI_VERSION == 1 @@ -3022,7 +3023,9 @@ namespace { "picker_log", "session_error", "dht_live_nodes", "session_stats_header", "dht_sample_infohashes", "block_uploaded", "alerts_dropped", "socks5", - "file_prio", "oversized_file", "torrent_conflict" + "file_prio", "oversized_file", "torrent_conflict", + "peer_info", "file_progress", "piece_info", + "piece_availability", "tracker_list" }}; TORRENT_ASSERT(alert_type >= 0); @@ -3110,6 +3113,82 @@ namespace { #endif } + peer_info_alert::peer_info_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector p) + : torrent_alert(alloc, std::move(h)) + , peer_info(std::move(p)) + {} + + std::string peer_info_alert::message() const + { +#ifdef TORRENT_DISABLE_ALERT_MSG + return {}; +#else + return torrent_alert::message() + " peer_info"; +#endif + } + + file_progress_alert::file_progress_alert(aux::stack_allocator& alloc, torrent_handle h + , aux::vector fp) + : torrent_alert(alloc, std::move(h)) + , files(std::move(fp)) + {} + + std::string file_progress_alert::message() const + { +#ifdef TORRENT_DISABLE_ALERT_MSG + return {}; +#else + return torrent_alert::message() + " file_progress"; +#endif + } + + piece_info_alert::piece_info_alert(aux::stack_allocator& alloc, torrent_handle h + , std::vector pi, std::vector&& bd) + : torrent_alert(alloc, std::move(h)) + , piece_info(std::move(pi)) + , block_data(std::move(bd)) + {} + + std::string piece_info_alert::message() const + { +#ifdef TORRENT_DISABLE_ALERT_MSG + return {}; +#else + return torrent_alert::message() + " piece_info"; +#endif + } + + piece_availability_alert::piece_availability_alert(aux::stack_allocator& alloc + , torrent_handle h, std::vector pa) + : torrent_alert(alloc, std::move(h)) + , piece_availability(std::move(pa)) + {} + + std::string piece_availability_alert::message() const + { +#ifdef TORRENT_DISABLE_ALERT_MSG + return {}; +#else + return torrent_alert::message() + " piece_availability"; +#endif + } + + tracker_list_alert::tracker_list_alert(aux::stack_allocator& alloc + , torrent_handle h, std::vector t) + : torrent_alert(alloc, std::move(h)) + , trackers(std::move(t)) + {} + + std::string tracker_list_alert::message() const + { +#ifdef TORRENT_DISABLE_ALERT_MSG + return {}; +#else + return torrent_alert::message() + " tracker_list"; +#endif + } + // this will no longer be necessary in C++17 constexpr alert_category_t torrent_removed_alert::static_category; constexpr alert_category_t read_piece_alert::static_category; @@ -3204,6 +3283,11 @@ namespace { constexpr alert_category_t file_prio_alert::static_category; constexpr alert_category_t oversized_file_alert::static_category; constexpr alert_category_t torrent_conflict_alert::static_category; + constexpr alert_category_t peer_info_alert::static_category; + constexpr alert_category_t file_progress_alert::static_category; + constexpr alert_category_t piece_info_alert::static_category; + constexpr alert_category_t piece_availability_alert::static_category; + constexpr alert_category_t tracker_list_alert::static_category; #if TORRENT_ABI_VERSION == 1 constexpr alert_category_t anonymous_mode_alert::static_category; constexpr alert_category_t mmap_cache_alert::static_category; diff --git a/3rd/libtorrent-rasterbar/src/assert.cpp b/3rd/libtorrent-rasterbar/src/assert.cpp index d623605b..48234545 100644 --- a/3rd/libtorrent-rasterbar/src/assert.cpp +++ b/3rd/libtorrent-rasterbar/src/assert.cpp @@ -190,16 +190,21 @@ TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth std::array stack; STACKFRAME64 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 +#if defined(_M_IX86) 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; +#elif defined(_M_X64) + 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; +#elif defined(_M_ARM64) + int const machine_type = IMAGE_FILE_MACHINE_ARM64; + stack_frame.AddrPC.Offset = context_record.Pc; + stack_frame.AddrFrame.Offset = context_record.Fp; + stack_frame.AddrStack.Offset = context_record.Sp; #endif stack_frame.AddrPC.Mode = AddrModeFlat; stack_frame.AddrFrame.Mode = AddrModeFlat; diff --git a/3rd/libtorrent-rasterbar/src/bitfield.cpp b/3rd/libtorrent-rasterbar/src/bitfield.cpp index 6e9604dc..1e3353b3 100644 --- a/3rd/libtorrent-rasterbar/src/bitfield.cpp +++ b/3rd/libtorrent-rasterbar/src/bitfield.cpp @@ -60,6 +60,20 @@ namespace libtorrent { return true; } + bool bitfield::operator==(lt::bitfield const& rhs) const + { + if (m_buf == rhs.m_buf) + return true; + + if (size() != rhs.size()) + return false; + + std::uint32_t const* lb = buf(); + std::uint32_t const* rb = rhs.buf(); + + return std::memcmp(lb, rb, std::size_t(num_words()) * 4) == 0; + } + int bitfield::count() const noexcept { int ret = 0; diff --git a/3rd/libtorrent-rasterbar/src/bt_peer_connection.cpp b/3rd/libtorrent-rasterbar/src/bt_peer_connection.cpp index 26142127..fa480c06 100644 --- a/3rd/libtorrent-rasterbar/src/bt_peer_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/bt_peer_connection.cpp @@ -222,10 +222,10 @@ namespace { out_policy = settings_pack::pe_disabled; #endif #ifndef TORRENT_DISABLE_LOGGING - static char const* policy_name[] = {"forced", "enabled", "disabled"}; - TORRENT_ASSERT(out_policy < sizeof(policy_name)/sizeof(policy_name[0])); + static char const* policy_name[] = {"forced", "enabled", "disabled", "invalid-setting"}; + int const policy_name_idx = out_policy > 3 ? 3 : out_policy; peer_log(peer_log_alert::info, "ENCRYPTION" - , "outgoing encryption policy: %s", policy_name[out_policy]); + , "outgoing encryption policy: %s", policy_name[policy_name_idx]); #endif if (out_policy == settings_pack::pe_forced) @@ -270,11 +270,15 @@ namespace { setup_receive(); } } - else if (out_policy == settings_pack::pe_disabled) + else #endif { +#if !defined TORRENT_DISABLE_ENCRYPTION + TORRENT_ASSERT(out_policy == settings_pack::pe_disabled); +#endif write_handshake(); + TORRENT_ASSERT(m_sent_handshake); // start in the state where we are trying to read the // handshake from the other side m_recv_buffer.reset(20); @@ -481,7 +485,27 @@ namespace { if (support_extensions()) p.flags |= peer_info::supports_extensions; if (is_outgoing()) p.flags |= peer_info::local_connection; #if TORRENT_USE_I2P - if (is_i2p(get_socket())) p.flags |= peer_info::i2p_socket; + if (is_i2p(get_socket())) + { + p.flags |= peer_info::i2p_socket; + auto const* pi = peer_info_struct(); + if (pi != nullptr) + { + try + { + sha256_hash const b32_addr = hasher256(base64decode_i2p(pi->dest())).final(); + p.set_i2p_destination(b32_addr); + } + catch (lt::system_error const&) + { + p.set_i2p_destination(sha256_hash()); + } + } + else + { + p.set_i2p_destination(sha256_hash()); + } + } #endif if (is_utp(get_socket())) p.flags |= peer_info::utp_socket; if (is_ssl(get_socket())) p.flags |= peer_info::ssl_socket; @@ -3273,6 +3297,8 @@ namespace { if (m_state == state_t::read_protocol_identifier) { + TORRENT_ASSERT(!m_outgoing || m_sent_handshake); + received_bytes(0, int(bytes_transferred)); bytes_transferred = 0; TORRENT_ASSERT(m_recv_buffer.packet_size() == 20); @@ -3359,6 +3385,7 @@ namespace { #endif } + TORRENT_ASSERT(!m_outgoing || m_sent_handshake); m_state = state_t::read_info_hash; m_recv_buffer.reset(28); } diff --git a/3rd/libtorrent-rasterbar/src/create_torrent.cpp b/3rd/libtorrent-rasterbar/src/create_torrent.cpp index 8182a1e6..dfddb43e 100644 --- a/3rd/libtorrent-rasterbar/src/create_torrent.cpp +++ b/3rd/libtorrent-rasterbar/src/create_torrent.cpp @@ -77,6 +77,7 @@ namespace libtorrent { constexpr create_flags_t create_torrent::canonical_files; constexpr create_flags_t create_torrent::no_attributes; constexpr create_flags_t create_torrent::canonical_files_no_tail_padding; + constexpr create_flags_t create_torrent::allow_odd_piece_size; namespace { @@ -446,7 +447,8 @@ namespace { aux::throw_ex(errors::invalid_piece_size); } else if ((piece_size % (16 * 1024)) != 0 - && (piece_size & (piece_size - 1)) != 0) + && (piece_size & (piece_size - 1)) != 0 + && !(flags & allow_odd_piece_size)) { // v1 torrents should have piece sizes divisible by 16 kiB aux::throw_ex(errors::invalid_piece_size); diff --git a/3rd/libtorrent-rasterbar/src/disk_buffer_pool.cpp b/3rd/libtorrent-rasterbar/src/disk_buffer_pool.cpp index e143d926..b904662d 100644 --- a/3rd/libtorrent-rasterbar/src/disk_buffer_pool.cpp +++ b/3rd/libtorrent-rasterbar/src/disk_buffer_pool.cpp @@ -50,6 +50,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #endif +#ifdef TORRENT_ADDRESS_SANITIZER +#include +#endif + #include "libtorrent/aux_/disable_warnings_pop.hpp" namespace libtorrent { diff --git a/3rd/libtorrent-rasterbar/src/drive_info.cpp b/3rd/libtorrent-rasterbar/src/drive_info.cpp index 74015c85..766bfa07 100644 --- a/3rd/libtorrent-rasterbar/src/drive_info.cpp +++ b/3rd/libtorrent-rasterbar/src/drive_info.cpp @@ -243,6 +243,7 @@ drive_info get_drive_info(std::string const& path) if (dev.handle() == INVALID_HANDLE_VALUE) continue; +#if _WIN32_WINNT >= 0x601 STORAGE_PROPERTY_QUERY query{}; query.PropertyId = StorageDeviceSeekPenaltyProperty; query.QueryType = PropertyExistsQuery; @@ -262,6 +263,7 @@ drive_info get_drive_info(std::string const& path) { seek_penalty = false; } +#endif } if (seek_penalty && !*seek_penalty) return drive_info::ssd_disk; diff --git a/3rd/libtorrent-rasterbar/src/escape_string.cpp b/3rd/libtorrent-rasterbar/src/escape_string.cpp index 1a0d789b..28a79f1e 100644 --- a/3rd/libtorrent-rasterbar/src/escape_string.cpp +++ b/3rd/libtorrent-rasterbar/src/escape_string.cpp @@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef TORRENT_WINDOWS #include "libtorrent/aux_/windows.hpp" @@ -54,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/escape_string.hpp" #include "libtorrent/string_util.hpp" // for to_string #include "libtorrent/aux_/array.hpp" +#include "libtorrent/aux_/byteswap.hpp" namespace libtorrent { @@ -297,23 +299,70 @@ namespace libtorrent { } #if TORRENT_USE_I2P - std::string base32encode(string_view s, encode_string_flags_t const flags) + +namespace { + std::uint32_t map_base64_char(char const c) + { + if (c >= 'A' && c <= 'Z') + return std::uint32_t(c - 'A'); + if (c >= 'a' && c <= 'z') + return std::uint32_t(26 + c - 'a'); + if (c >= '0' && c <= '9') + return std::uint32_t(52 + c - '0'); + if (c == '-') return 62; + if (c == '~') return 63; + throw system_error(error_code(lt::errors::invalid_escaped_string)); + } +} + + // this decodes the i2p alphabet + std::vector base64decode_i2p(string_view s) { - static char const base32_table_canonical[] = + std::uint32_t output = 0; + + std::vector ret; + int bit_offset = 18; + for (auto const c : s) { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '2', '3', '4', '5', '6', '7' - }; - static char const base32_table_lowercase[] = + if (c == '=') break; + output |= map_base64_char(c) << bit_offset; + if (bit_offset == 0) + { + output = aux::host_to_network(output); + aux::array tmp; + std::memcpy(tmp.data(), &output, 4); + ret.push_back(tmp[1]); + ret.push_back(tmp[2]); + ret.push_back(tmp[3]); + output = 0; + bit_offset = 18; + } + else + { + bit_offset -= 6; + } + } + if (bit_offset < 18) + { + output = aux::host_to_network(output); + aux::array tmp; + std::memcpy(tmp.data(), &output, 4); + ret.push_back(tmp[1]); + if (bit_offset < 6) + ret.push_back(tmp[2]); + } + return ret; + } + + std::string base32encode_i2p(span s) + { + static char const base32_table[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '2', '3', '4', '5', '6', '7' }; - char const *base32_table = (flags & string::lowercase) ? base32_table_lowercase : base32_table_canonical; static aux::array const input_output_mapping{{{0, 2, 4, 5, 7, 8}}}; @@ -323,7 +372,7 @@ namespace libtorrent { std::string ret; for (auto i = s.begin(); i != s.end();) { - int available_input = std::min(int(inbuf.size()), int(s.end() - i)); + int const available_input = std::min(int(inbuf.size()), int(s.end() - i)); // clear input buffer inbuf.fill(0); @@ -345,18 +394,8 @@ namespace libtorrent { // write output int const num_out = input_output_mapping[available_input]; for (int j = 0; j < num_out; ++j) - { ret += base32_table[outbuf[j]]; - } - - if (!(flags & string::no_padding)) - { - // write pad - for (int j = 0; j < int(outbuf.size()) - num_out; ++j) - { - ret += '='; - } - } + // i2p does not use padding } return ret; } diff --git a/3rd/libtorrent-rasterbar/src/file.cpp b/3rd/libtorrent-rasterbar/src/file.cpp index f093b3bb..7b5ddee7 100644 --- a/3rd/libtorrent-rasterbar/src/file.cpp +++ b/3rd/libtorrent-rasterbar/src/file.cpp @@ -499,7 +499,7 @@ file_handle::file_handle(string_view name, std::int64_t const size int const ret = ::posix_fallocate(m_fd, 0, size); // posix_allocate fails with EINVAL in case the underlying // filesystem does not support this operation - if (ret != 0 && ret != EINVAL) + if (ret != 0 && ret != EINVAL && ret != ENOTSUP) { ::close(m_fd); throw_ex(error_code(ret, system_category()), operation_t::file_fallocate); @@ -512,8 +512,11 @@ file_handle::file_handle(string_view name, std::int64_t const size if (fcntl(m_fd, F_ALLOCSP64, &fl64) < 0) { int const err = errno; - ::close(m_fd); - throw_ex(error_code(ret, system_category()), operation_t::file_fallocate); + if (err != ENOTSUP) + { + ::close(m_fd); + throw_ex(error_code(err, system_category()), operation_t::file_fallocate); + } } #elif defined F_PREALLOCATE fstore_t f = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, size, 0}; @@ -522,11 +525,11 @@ file_handle::file_handle(string_view name, std::int64_t const size // It appears Apple's new filesystem (APFS) does not // support this control message and fails with EINVAL // if so, just skip it - if (errno != EINVAL) + int const err = errno; + if (err != EINVAL && err != ENOTSUP) { - if (errno != ENOSPC) + if (err != ENOSPC) { - int const err = errno; ::close(m_fd); throw_ex(error_code(err, system_category()) , operation_t::file_fallocate); @@ -535,9 +538,9 @@ file_handle::file_handle(string_view name, std::int64_t const size f.fst_flags = F_ALLOCATEALL; if (fcntl(m_fd, F_PREALLOCATE, &f) < 0) { - int const err = errno; + int const err2 = errno; ::close(m_fd); - throw_ex(error_code(err, system_category()) + throw_ex(error_code(err2, system_category()) , operation_t::file_fallocate); } } diff --git a/3rd/libtorrent-rasterbar/src/file_progress.cpp b/3rd/libtorrent-rasterbar/src/file_progress.cpp index 3bbe6de2..7a2156bc 100644 --- a/3rd/libtorrent-rasterbar/src/file_progress.cpp +++ b/3rd/libtorrent-rasterbar/src/file_progress.cpp @@ -194,6 +194,13 @@ namespace libtorrent { namespace aux { return; } +#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS + // if we have many files, this would be an expensive + // invariant check, so don't run it unless we + // enabled expensive invariant checks + if (m_file_progress.size() > 900) return; +#endif + file_index_t index(0); std::int64_t total_on_disk = 0; for (std::int64_t progress : m_file_progress) diff --git a/3rd/libtorrent-rasterbar/src/file_storage.cpp b/3rd/libtorrent-rasterbar/src/file_storage.cpp index b157bec1..36f181b8 100644 --- a/3rd/libtorrent-rasterbar/src/file_storage.cpp +++ b/3rd/libtorrent-rasterbar/src/file_storage.cpp @@ -151,6 +151,11 @@ namespace { return (piece_size2(index) + default_block_size - 1) / default_block_size; } + int file_storage::blocks_per_piece() const + { + return (m_piece_length + default_block_size - 1) / default_block_size; + } + // path is supposed to include the name of the torrent itself. // or an absolute path, to move a file outside of the download directory void file_storage::update_path_index(aux::file_entry& e diff --git a/3rd/libtorrent-rasterbar/src/gzip.cpp b/3rd/libtorrent-rasterbar/src/gzip.cpp index 14735d1e..c09087d1 100644 --- a/3rd/libtorrent-rasterbar/src/gzip.cpp +++ b/3rd/libtorrent-rasterbar/src/gzip.cpp @@ -204,9 +204,12 @@ namespace { do { - TORRENT_TRY { + try + { buffer.resize(destlen); - } TORRENT_CATCH (std::exception const&) { + } + catch (std::exception const&) + { ec = errors::no_memory; return; } diff --git a/3rd/libtorrent-rasterbar/src/hash_picker.cpp b/3rd/libtorrent-rasterbar/src/hash_picker.cpp index 3fdd5d56..b301c296 100644 --- a/3rd/libtorrent-rasterbar/src/hash_picker.cpp +++ b/3rd/libtorrent-rasterbar/src/hash_picker.cpp @@ -292,9 +292,7 @@ bool validate_hash_request(hash_request const& hr, file_storage const& fs) auto const f = m_files.file_index_at_piece(piece); if (m_files.pad_file_at(f)) - { - return { 0, 0 }; - } + return { set_block_hash_result::result::success, 0, 0 }; auto& merkle_tree = m_merkle_trees[f]; piece_index_t const file_first_piece = m_files.piece_index_at_file(f); @@ -316,13 +314,17 @@ bool validate_hash_request(hash_request const& hr, file_storage const& fs) if (result == aux::merkle_tree::set_block_result::unknown) return set_block_hash_result::unknown(); - if (result == aux::merkle_tree::set_block_result::hash_failed) - return set_block_hash_result::piece_hash_failed(); if (result == aux::merkle_tree::set_block_result::block_hash_failed) - return set_block_hash_result::block_hash_failed(); + return set_block_hash_result::block_hash_failed(); + + auto const status = (result == aux::merkle_tree::set_block_result::hash_failed) + ? set_block_hash_result::result::piece_hash_failed + : set_block_hash_result::result::success; int const blocks_per_piece = m_files.piece_length() / default_block_size; - return { int(leafs_index - static_cast(piece - file_first_piece) * blocks_per_piece) + + return { status + , int(leafs_index - static_cast(piece - file_first_piece) * blocks_per_piece) , std::min(leafs_size, m_files.file_num_pieces(f) * blocks_per_piece - leafs_index) }; } diff --git a/3rd/libtorrent-rasterbar/src/http_connection.cpp b/3rd/libtorrent-rasterbar/src/http_connection.cpp index 0e05e4d1..b47f76b8 100644 --- a/3rd/libtorrent-rasterbar/src/http_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/http_connection.cpp @@ -368,11 +368,11 @@ void http_connection::start(std::string const& hostname, int port } else #endif - m_hostname = hostname; if (ps && ps->proxy_hostnames && (ps->type == settings_pack::socks5 || ps->type == settings_pack::socks5_pw)) { + m_hostname = hostname; m_port = std::uint16_t(port); m_endpoints.emplace_back(address(), m_port); connect(); @@ -385,6 +385,7 @@ void http_connection::start(std::string const& hostname, int port , std::bind(&http_connection::on_resolve , me, _1, _2)); } + m_hostname = hostname; m_port = std::uint16_t(port); } } diff --git a/3rd/libtorrent-rasterbar/src/http_seed_connection.cpp b/3rd/libtorrent-rasterbar/src/http_seed_connection.cpp index 8905f612..03daf4aa 100644 --- a/3rd/libtorrent-rasterbar/src/http_seed_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/http_seed_connection.cpp @@ -79,6 +79,21 @@ namespace libtorrent { #endif } + void http_seed_connection::disable(error_code const& ec) + { + // we should not try this server again. + m_web->disabled = true; + disconnect(ec, operation_t::bittorrent, peer_error); + if (m_web->ephemeral) + { + std::shared_ptr t = associated_torrent().lock(); + TORRENT_ASSERT(t); + t->remove_web_seed_conn(this); + } + m_web = nullptr; + TORRENT_ASSERT(is_disconnecting()); + } + void http_seed_connection::on_connected() { peer_id pid; @@ -104,7 +119,8 @@ namespace libtorrent { std::shared_ptr t = associated_torrent().lock(); peer_connection::disconnect(ec, op, error); - if (t) t->disconnect_web_seed(this); + TORRENT_ASSERT(m_web->resolving == false); + m_web->peer_info.connection = nullptr; } piece_block_progress http_seed_connection::downloading_piece_progress() const @@ -322,7 +338,7 @@ namespace libtorrent { if (location.empty()) { // we should not try this server again. - t->remove_web_seed_conn(this, errors::missing_location, operation_t::bittorrent, peer_error); + disable(errors::missing_location); return; } @@ -337,7 +353,7 @@ namespace libtorrent { t->add_web_seed(location, web_seed_entry::http_seed , std::string{}, web_seed_entry::headers_t{} , web_seed_flags); - t->remove_web_seed_conn(this, errors::redirecting, operation_t::bittorrent, peer_error); + disable(errors::redirecting); return; } @@ -352,14 +368,14 @@ namespace libtorrent { { received_bytes(0, int(bytes_transferred)); // we should not try this server again. - t->remove_web_seed_conn(this, errors::no_content_length, operation_t::bittorrent, peer_error); + disable(errors::no_content_length); return; } if (m_response_left != front_request.length) { received_bytes(0, int(bytes_transferred)); // we should not try this server again. - t->remove_web_seed_conn(this, errors::invalid_range, operation_t::bittorrent, peer_error); + disable(errors::invalid_range); return; } m_body_start = m_parser.body_start(); diff --git a/3rd/libtorrent-rasterbar/src/http_tracker_connection.cpp b/3rd/libtorrent-rasterbar/src/http_tracker_connection.cpp index c25301ab..d7b66c57 100644 --- a/3rd/libtorrent-rasterbar/src/http_tracker_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/http_tracker_connection.cpp @@ -214,7 +214,9 @@ namespace libtorrent { } } - if (!tracker_req().outgoing_socket) + // i2p trackers don't use our outgoing sockets, they use the SAM + // connection + if (!i2p && !tracker_req().outgoing_socket) { fail(errors::invalid_listen_socket, operation_t::get_interface , "outgoing socket was closed"); @@ -247,7 +249,12 @@ namespace libtorrent { : settings.get_str(settings_pack::user_agent); auto const ls = bind_socket(); - bind_info_t bi{ls.device(), ls.get_local_endpoint().address()}; + bind_info_t bi = [&ls](){ + if (ls.get() == nullptr) + return bind_info_t{}; + else + return bind_info_t{ls.device(), ls.get_local_endpoint().address()}; + }(); // when sending stopped requests, prefer the cached DNS entry // to avoid being blocked for slow or failing responses. Chances @@ -302,9 +309,12 @@ namespace libtorrent { // be all of them, in which case we should not announce this listen socket // to this tracker auto const ls = bind_socket(); - endpoints.erase(std::remove_if(endpoints.begin(), endpoints.end() - , [&](tcp::endpoint const& ep) { return !ls.can_route(ep.address()); }) - , endpoints.end()); + if (ls.get() != nullptr) + { + endpoints.erase(std::remove_if(endpoints.begin(), endpoints.end() + , [&](tcp::endpoint const& ep) { return !ls.can_route(ep.address()); }) + , endpoints.end()); + } if (endpoints.empty()) { @@ -587,11 +597,9 @@ namespace libtorrent { for (int i = 0; i < len; i += 32) { if (len - i < 32) break; - peer_entry p; - p.hostname = base32encode(std::string(peers + i, 32), string::i2p); - p.hostname += ".b32.i2p"; - p.port = 6881; - resp.peers.push_back(p); + i2p_peer_entry p; + std::memcpy(p.destination.data(), peers + i, 32); + resp.i2p_peers.push_back(p); } } else diff --git a/3rd/libtorrent-rasterbar/src/i2p_stream.cpp b/3rd/libtorrent-rasterbar/src/i2p_stream.cpp index e52fb062..acf20f4f 100644 --- a/3rd/libtorrent-rasterbar/src/i2p_stream.cpp +++ b/3rd/libtorrent-rasterbar/src/i2p_stream.cpp @@ -117,14 +117,9 @@ namespace libtorrent { i2p_stream::i2p_stream(io_context& io_context) : proxy_base(io_context) - , m_id(nullptr) , m_command(cmd_create_session) , m_state(read_hello_response) - { -#if TORRENT_USE_ASSERTS - m_magic = 0x1337; -#endif - } + {} #if TORRENT_USE_ASSERTS i2p_stream::~i2p_stream() diff --git a/3rd/libtorrent-rasterbar/src/ip_helpers.cpp b/3rd/libtorrent-rasterbar/src/ip_helpers.cpp index f317e297..29dc2ce0 100644 --- a/3rd/libtorrent-rasterbar/src/ip_helpers.cpp +++ b/3rd/libtorrent-rasterbar/src/ip_helpers.cpp @@ -77,7 +77,8 @@ namespace aux { bool is_local(address const& a) { - TORRENT_TRY { + try + { if (a.is_v6()) { // NOTE: site local is deprecated but by @@ -100,18 +101,23 @@ namespace aux { || (ip & 0xfff00000) == 0xac100000 // 172.16.x.x || (ip & 0xffff0000) == 0xc0a80000 // 192.168.x.x || (ip & 0xffff0000) == 0xa9fe0000 // 169.254.x.x - || (ip & 0xff000000) == 0x7f000000); // 127.x.x.x - } TORRENT_CATCH(std::exception const&) { return false; } + || (ip & 0xff000000) == 0x7f000000 // 127.x.x.x + || (ip & 0xffc00000) == 0x64400000 // 100.64.0.0/10 + ); + } + catch (std::exception const&) { return false; } } bool is_teredo(address const& addr) { - TORRENT_TRY { + try + { if (!addr.is_v6()) return false; static const std::uint8_t teredo_prefix[] = {0x20, 0x01, 0, 0}; address_v6::bytes_type b = addr.to_v6().to_bytes(); return std::memcmp(b.data(), teredo_prefix, 4) == 0; - } TORRENT_CATCH(std::exception const&) { return false; } + } + catch (std::exception const&) { return false; } } address ensure_v6(address const& a) diff --git a/3rd/libtorrent-rasterbar/src/ip_notifier.cpp b/3rd/libtorrent-rasterbar/src/ip_notifier.cpp index cb77be4c..15a05836 100644 --- a/3rd/libtorrent-rasterbar/src/ip_notifier.cpp +++ b/3rd/libtorrent-rasterbar/src/ip_notifier.cpp @@ -44,7 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include #include -#elif TORRENT_USE_SYSTEMCONFIGURATION +#elif TORRENT_USE_SYSTEMCONFIGURATION || TORRENT_USE_SC_NETWORK_REACHABILITY #include #elif defined TORRENT_WINDOWS #include "libtorrent/aux_/throw.hpp" @@ -63,6 +63,59 @@ namespace libtorrent { namespace aux { namespace { +#if (TORRENT_USE_SYSTEMCONFIGURATION || TORRENT_USE_SC_NETWORK_REACHABILITY) && \ + !defined TORRENT_BUILD_SIMULATOR + +// common utilities for Mac and iOS +template void CFRefRetain(T h) { CFRetain(h); } +template void CFRefRelease(T h) { CFRelease(h); } + +template , void (*Release)(T) = CFRefRelease> +struct CFRef +{ + CFRef() = default; + explicit CFRef(T h) : m_h(h) {} // take ownership + ~CFRef() { release(); } + + CFRef(CFRef&& rhs) : m_h(rhs.m_h) { rhs.m_h = nullptr; } + CFRef& operator=(CFRef&& rhs) & + { + if (m_h == rhs.m_h) return *this; + release(); + m_h = rhs.m_h; + rhs.m_h = nullptr; + return *this; + } + + CFRef(CFRef const& rhs) : m_h(rhs.m_h) { retain(); } + CFRef& operator=(CFRef const& rhs) & + { + if (m_h == rhs.m_h) return *this; + release(); + m_h = rhs.m_h; + retain(); + return *this; + } + + CFRef& operator=(T h) & { m_h = h; return *this;} + CFRef& operator=(std::nullptr_t) & { release(); return *this;} + + T get() const { return m_h; } + explicit operator bool() const { return m_h != nullptr; } + +private: + T m_h = nullptr; // handle + + void retain() { if (m_h != nullptr) Retain(m_h); } + void release() { if (m_h != nullptr) Release(m_h); m_h = nullptr; } +}; + +void CFDispatchRetain(dispatch_queue_t q) { dispatch_retain(q); } +void CFDispatchRelease(dispatch_queue_t q) { dispatch_release(q); } +using CFDispatchRef = CFRef; +#endif + #if defined TORRENT_BUILD_SIMULATOR struct ip_change_notifier_impl final : ip_change_notifier { @@ -179,57 +232,9 @@ struct ip_change_notifier_impl final : ip_change_notifier } } }; -#elif TORRENT_USE_SYSTEMCONFIGURATION - -template void CFRefRetain(T h) { CFRetain(h); } -template void CFRefRelease(T h) { CFRelease(h); } - -template , void (*Release)(T) = CFRefRelease> -struct CFRef -{ - CFRef() = default; - explicit CFRef(T h) : m_h(h) {} // take ownership - ~CFRef() { release(); } - - CFRef(CFRef&& rhs) : m_h(rhs.m_h) { rhs.m_h = nullptr; } - CFRef& operator=(CFRef&& rhs) & - { - if (m_h == rhs.m_h) return *this; - release(); - m_h = rhs.m_h; - rhs.m_h = nullptr; - return *this; - } - - CFRef(CFRef const& rhs) : m_h(rhs.m_h) { retain(); } - CFRef& operator=(CFRef const& rhs) & - { - if (m_h == rhs.m_h) return *this; - release(); - m_h = rhs.m_h; - retain(); - return *this; - } - CFRef& operator=(T h) & { m_h = h; return *this;} - CFRef& operator=(std::nullptr_t) & { release(); return *this;} - - T get() const { return m_h; } - explicit operator bool() const { return m_h != nullptr; } +#elif TORRENT_USE_SC_NETWORK_REACHABILITY -private: - T m_h = nullptr; // handle - - void retain() { if (m_h != nullptr) Retain(m_h); } - void release() { if (m_h != nullptr) Release(m_h); m_h = nullptr; } -}; - -void CFDispatchRetain(dispatch_queue_t q) { dispatch_retain(q); } -void CFDispatchRelease(dispatch_queue_t q) { dispatch_release(q); } -using CFDispatchRef = CFRef; - -#if TORRENT_USE_SC_NETWORK_REACHABILITY CFRef create_reachability(SCNetworkReachabilityCallBack callback , void* context_info) { @@ -307,7 +312,7 @@ struct ip_change_notifier_impl final : ip_change_notifier CFRef m_reach; std::function m_cb = nullptr; }; -#else +#elif TORRENT_USE_SYSTEMCONFIGURATION // see https://developer.apple.com/library/content/technotes/tn1145/_index.html CFRef create_keys_array() { @@ -407,7 +412,6 @@ struct ip_change_notifier_impl final : ip_change_notifier CFRef m_store; std::function m_cb = nullptr; }; -#endif // TORRENT_USE_SC_NETWORK_REACHABILITY #elif defined TORRENT_WINDOWS struct ip_change_notifier_impl final : ip_change_notifier diff --git a/3rd/libtorrent-rasterbar/src/kademlia/get_peers.cpp b/3rd/libtorrent-rasterbar/src/kademlia/get_peers.cpp index ea4713b8..bc2b3507 100644 --- a/3rd/libtorrent-rasterbar/src/kademlia/get_peers.cpp +++ b/3rd/libtorrent-rasterbar/src/kademlia/get_peers.cpp @@ -209,27 +209,6 @@ bool obfuscated_get_peers::invoke(observer_ptr o) node_id const& id = o->id(); int const shared_prefix = 160 - distance_exp(id, target()); - // when we get close to the target zone in the DHT - // start using the correct info-hash, in order to - // start receiving peers - if (shared_prefix > m_node.m_table.depth() - 4) - { - m_obfuscated = false; - // clear the queried bits on all successful nodes in - // our node-list for this traversal algorithm, to - // allow the get_peers traversal to regress in case - // nodes further down end up being dead - for (auto const& node : m_results) - { - // don't re-request from nodes that didn't respond - if (node->flags & observer::flag_failed) continue; - // don't interrupt with queries that are already in-flight - if (!(node->flags & observer::flag_alive)) continue; - node->flags &= ~(observer::flag_queried | observer::flag_alive); - } - return get_peers::invoke(o); - } - entry e; e["y"] = "q"; e["q"] = "get_peers"; diff --git a/3rd/libtorrent-rasterbar/src/kademlia/node.cpp b/3rd/libtorrent-rasterbar/src/kademlia/node.cpp index 0fc7b959..d2bab1b9 100644 --- a/3rd/libtorrent-rasterbar/src/kademlia/node.cpp +++ b/3rd/libtorrent-rasterbar/src/kademlia/node.cpp @@ -402,6 +402,7 @@ namespace { a["seed"] = (flags & announce::seed) ? 1 : 0; if (flags & announce::implied_port) a["implied_port"] = 1; node.stats_counters().inc_stats_counter(counters::dht_announce_peer_out); + o->flags |= observer::flag_queried; node.m_rpc.invoke(e, p.first.ep(), o); } } @@ -477,6 +478,7 @@ void node::direct_request(udp::endpoint const& ep, entry& e #if TORRENT_USE_ASSERTS o->m_in_constructor = false; #endif + o->flags |= observer::flag_queried; m_rpc.invoke(e, ep, o); } @@ -607,6 +609,7 @@ void node::sample_infohashes(udp::endpoint const& ep, sha1_hash const& target stats_counters().inc_stats_counter(counters::dht_sample_infohashes_out); + o->flags |= observer::flag_queried; m_rpc.invoke(e, ep, o); } @@ -709,6 +712,7 @@ void node::send_single_refresh(udp::endpoint const& ep, int const bucket m_counters.inc_stats_counter(counters::dht_get_peers_out); } + o->flags |= observer::flag_queried; m_rpc.invoke(e, ep, o); } diff --git a/3rd/libtorrent-rasterbar/src/kademlia/rpc_manager.cpp b/3rd/libtorrent-rasterbar/src/kademlia/rpc_manager.cpp index 0c4ccde5..adaf4095 100644 --- a/3rd/libtorrent-rasterbar/src/kademlia/rpc_manager.cpp +++ b/3rd/libtorrent-rasterbar/src/kademlia/rpc_manager.cpp @@ -118,13 +118,14 @@ void observer::abort() { if (flags & flag_done) return; flags |= flag_done; - m_algorithm->failed(self(), traversal_algorithm::prevent_request); + m_algorithm->abort(); + m_algorithm->failed(self()); } void observer::done() { if (flags & flag_done) return; - flags |= flag_done; + flags |= observer::flag_done; m_algorithm->finished(self()); } @@ -189,9 +190,7 @@ rpc_manager::~rpc_manager() m_destructing = true; for (auto const& t : m_transactions) - { t.second->abort(); - } } void* rpc_manager::allocate_observer() @@ -220,6 +219,10 @@ void rpc_manager::check_invariant() const { for (auto const& t : m_transactions) { + TORRENT_ASSERT(t.second->flags & observer::flag_queried); + if (!m_destructing) + TORRENT_ASSERT(!(t.second->flags & observer::flag_failed)); + TORRENT_ASSERT(!(t.second->flags & observer::flag_alive)); TORRENT_ASSERT(t.second); } } @@ -407,6 +410,13 @@ time_duration rpc_manager::tick() { observer_ptr o = i->second; + if (o->flags & observer::flag_done) + { + // remove cancelled requests + i = m_transactions.erase(i); + continue; + } + time_duration diff = now - o->sent(); if (diff >= timeout) { @@ -499,6 +509,7 @@ bool rpc_manager::invoke(entry& e, udp::endpoint const& target_addr { m_transactions.emplace(tid, o); #if TORRENT_USE_ASSERTS + TORRENT_ASSERT(o->flags & observer::flag_queried); o->m_was_sent = true; #endif return true; diff --git a/3rd/libtorrent-rasterbar/src/kademlia/traversal_algorithm.cpp b/3rd/libtorrent-rasterbar/src/kademlia/traversal_algorithm.cpp index 00825e3e..37c2556b 100644 --- a/3rd/libtorrent-rasterbar/src/kademlia/traversal_algorithm.cpp +++ b/3rd/libtorrent-rasterbar/src/kademlia/traversal_algorithm.cpp @@ -53,7 +53,6 @@ using namespace std::placeholders; namespace libtorrent { namespace dht { -constexpr traversal_flags_t traversal_algorithm::prevent_request; constexpr traversal_flags_t traversal_algorithm::short_timeout; #if TORRENT_USE_ASSERTS @@ -77,6 +76,7 @@ bool is_sorted(It b, It e, Cmp cmp) observer_ptr traversal_algorithm::new_observer(udp::endpoint const& ep , node_id const& id) { + INVARIANT_CHECK; auto o = m_node.m_rpc.allocate_observer(self(), ep, id); #if TORRENT_USE_ASSERTS if (o) o->m_in_constructor = false; @@ -88,6 +88,7 @@ traversal_algorithm::traversal_algorithm(node& dht_node, node_id const& target) : m_node(dht_node) , m_target(target) { + INVARIANT_CHECK; #ifndef TORRENT_DISABLE_LOGGING m_id = m_node.search_id(); dht_observer* logger = get_node().observer(); @@ -101,6 +102,7 @@ traversal_algorithm::traversal_algorithm(node& dht_node, node_id const& target) void traversal_algorithm::resort_result(observer* o) { + //INVARIANT_CHECK; // find the given observer, remove it and insert it in its sorted location auto it = std::find_if(m_results.begin(), m_results.end() , [=](observer_ptr const& ptr) { return ptr.get() == o; }); @@ -131,6 +133,7 @@ void traversal_algorithm::resort_result(observer* o) void traversal_algorithm::add_entry(node_id const& id , udp::endpoint const& addr, observer_flags_t const flags) { + INVARIANT_CHECK; if (m_done) return; TORRENT_ASSERT(m_node.m_rpc.allocation_size() >= sizeof(find_data_observer)); @@ -262,6 +265,12 @@ void traversal_algorithm::add_entry(node_id const& id ptr->flags |= observer::flag_done; TORRENT_ASSERT(m_invoke_count > 0); --m_invoke_count; + + if (ptr->flags & observer::flag_short_timeout) + { + TORRENT_ASSERT(m_branch_factor > 0); + --m_branch_factor; + } } #if TORRENT_USE_ASSERTS @@ -275,6 +284,7 @@ void traversal_algorithm::add_entry(node_id const& id void traversal_algorithm::start() { + INVARIANT_CHECK; // in case the routing table is empty, use the // router nodes in the table if (m_results.size() < 3) add_router_entries(); @@ -290,6 +300,7 @@ char const* traversal_algorithm::name() const void traversal_algorithm::traverse(node_id const& id, udp::endpoint const& addr) { + INVARIANT_CHECK; if (m_done) return; #ifndef TORRENT_DISABLE_LOGGING @@ -312,7 +323,7 @@ void traversal_algorithm::finished(observer_ptr o) { #if TORRENT_USE_ASSERTS auto i = std::find(m_results.begin(), m_results.end(), o); - TORRENT_ASSERT(i != m_results.end() || m_results.size() == 100); + TORRENT_ASSERT(i != m_results.end()); #endif // if this flag is set, it means we increased the @@ -323,7 +334,10 @@ void traversal_algorithm::finished(observer_ptr o) --m_branch_factor; } - TORRENT_ASSERT(o->flags & observer::flag_queried); + TORRENT_ASSERT((o->flags & (observer::flag_queried + | observer::flag_alive + | observer::flag_failed + )) == observer::flag_queried); o->flags |= observer::flag_alive; ++m_responses; @@ -382,13 +396,9 @@ void traversal_algorithm::failed(observer_ptr o, traversal_flags_t const flags) --m_invoke_count; } - // this is another reason to decrement the branch factor, to prevent another - // request from filling this slot. Only ever decrement once per response though - decrement_branch_factor |= bool(flags & prevent_request); - if (decrement_branch_factor) { - TORRENT_ASSERT(m_branch_factor > 0); + TORRENT_ASSERT(m_branch_factor > 1); --m_branch_factor; if (m_branch_factor <= 0) m_branch_factor = 1; } @@ -416,6 +426,7 @@ void traversal_algorithm::log_timeout(observer_ptr const& o, char const* prefix) void traversal_algorithm::done() { + INVARIANT_CHECK; TORRENT_ASSERT(m_done == false); m_done = true; #ifndef TORRENT_DISABLE_LOGGING @@ -425,6 +436,17 @@ void traversal_algorithm::done() for (auto const& o : m_results) { + if ((o->flags & (observer::flag_queried + | observer::flag_alive + | observer::flag_done + | observer::flag_failed + | observer::flag_short_timeout)) + == (observer::flag_queried | observer::flag_short_timeout)) + { + TORRENT_ASSERT(m_branch_factor > 0); + --m_branch_factor; + } + if ((o->flags & (observer::flag_queried | observer::flag_failed)) == observer::flag_queried) { // set the done flag on any outstanding queries to prevent them from @@ -469,6 +491,7 @@ void traversal_algorithm::done() bool traversal_algorithm::add_requests() { + INVARIANT_CHECK; if (m_done) return true; int results_target = m_node.m_table.bucket_size(); @@ -531,6 +554,10 @@ bool traversal_algorithm::add_requests() } #endif + // we're shutting down, don't issue any more lookups + if (m_abort) continue; + + TORRENT_ASSERT(!(o->flags & observer::flag_queried)); o->flags |= observer::flag_queried; if (invoke(*i)) { @@ -554,6 +581,7 @@ bool traversal_algorithm::add_requests() void traversal_algorithm::add_router_entries() { + INVARIANT_CHECK; #ifndef TORRENT_DISABLE_LOGGING dht_observer* logger = get_node().observer(); if (logger != nullptr && logger->should_log(dht_logger::traversal)) @@ -569,17 +597,24 @@ void traversal_algorithm::add_router_entries() void traversal_algorithm::init() { + INVARIANT_CHECK; m_branch_factor = aux::numeric_cast(m_node.branch_factor()); m_node.add_traversal_algorithm(this); + +#if TORRENT_USE_ASSERTS + m_initialized = true; +#endif } traversal_algorithm::~traversal_algorithm() { + INVARIANT_CHECK; m_node.remove_traversal_algorithm(this); } void traversal_algorithm::status(dht_lookup& l) { + INVARIANT_CHECK; l.timeouts = m_timeouts; l.responses = m_responses; l.outstanding_requests = m_invoke_count; @@ -605,6 +640,51 @@ void traversal_algorithm::status(dht_lookup& l) l.last_sent = last_sent; } +#if TORRENT_USE_INVARIANT_CHECKS +void traversal_algorithm::check_invariant() const +{ + int outstanding_requests = 0; + int outstanding_short_timeout = 0; + + for (auto const& r : m_results) + { + observer const& o = *r; + if ((o.flags & (observer::flag_short_timeout + | observer::flag_alive + | observer::flag_failed + | observer::flag_done)) + == observer::flag_short_timeout) + { + ++outstanding_short_timeout; + } + + if ((o.flags & (observer::flag_queried + | observer::flag_alive + | observer::flag_done + | observer::flag_failed)) + == observer::flag_queried) + { + ++outstanding_requests; + } + +#if TORRENT_USE_ASSERTS + TORRENT_ASSERT(!o.m_in_constructor); + TORRENT_ASSERT(o.m_in_use); + TORRENT_ASSERT(o.m_was_sent == bool(o.flags & observer::flag_queried) || (o.flags & observer::flag_failed)); + if (o.m_was_abandoned) + TORRENT_ASSERT(o.flags & observer::flag_done); +#endif + } + + if (m_initialized) + { + int const default_branch_factor = aux::numeric_cast(m_node.branch_factor()); + TORRENT_ASSERT(outstanding_short_timeout + default_branch_factor == m_branch_factor); + } + TORRENT_ASSERT(outstanding_requests == m_invoke_count); +} +#endif + void look_for_nodes(char const* nodes_key, udp const& protocol, bdecode_node const& r, std::function f) { bdecode_node const n = r.dict_find_string(nodes_key); @@ -626,6 +706,7 @@ void traversal_observer::reply(msg const& m) bdecode_node const r = m.message.dict_find_dict("r"); if (!r) { + timeout(); #ifndef TORRENT_DISABLE_LOGGING if (get_observer() != nullptr) { @@ -657,6 +738,7 @@ void traversal_observer::reply(msg const& m) if (!id || id.string_length() != 20) { + timeout(); #ifndef TORRENT_DISABLE_LOGGING if (get_observer() != nullptr) { diff --git a/3rd/libtorrent-rasterbar/src/load_torrent.cpp b/3rd/libtorrent-rasterbar/src/load_torrent.cpp index 4d4e6f0c..9232daa4 100644 --- a/3rd/libtorrent-rasterbar/src/load_torrent.cpp +++ b/3rd/libtorrent-rasterbar/src/load_torrent.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/file_storage.hpp" #include "libtorrent/sha1_hash.hpp" #include "libtorrent/aux_/merkle.hpp" +#include "libtorrent/aux_/throw.hpp" namespace libtorrent { @@ -42,26 +43,32 @@ namespace { void update_atp(add_torrent_params& atp) { auto const& ti = atp.ti; - for (auto const& ae : ti->trackers()) + // This is a temporary measure until all non info-dict content is parsed + // here, rather than the torrent_info constructor + auto drained_state = ti->_internal_drain(); + for (auto const& ae : drained_state.urls) { - atp.trackers.push_back(ae.url); + atp.trackers.push_back(std::move(ae.url)); atp.tracker_tiers.push_back(ae.tier); } - ti->clear_trackers(); + if (ti->is_i2p()) + atp.flags |= torrent_flags::i2p_torrent; - for (auto const& ws : ti->web_seeds()) + for (auto const& ws : drained_state.web_seeds) { if (ws.type == web_seed_entry::url_seed) - atp.url_seeds.push_back(ws.url); + atp.url_seeds.push_back(std::move(ws.url)); else if (ws.type == web_seed_entry::http_seed) - atp.http_seeds.push_back(ws.url); + atp.http_seeds.push_back(std::move(ws.url)); } - ti->clear_web_seeds(); - atp.dht_nodes = ti->nodes(); + atp.dht_nodes = std::move(drained_state.nodes); if (ti->v2_piece_hashes_verified()) { + int const blocks_per_piece = ti->files().blocks_per_piece(); + std::vector scratch; + sha256_hash const pad = merkle_pad(blocks_per_piece, 1); file_storage const& fs = ti->files(); atp.merkle_trees.resize(fs.num_files()); atp.merkle_tree_mask.resize(fs.num_files()); @@ -74,12 +81,23 @@ namespace { layer.reserve(std::size_t(bytes.size() / sha256_hash::size())); for (int i = 0; i < bytes.size(); i += int(sha256_hash::size())) layer.emplace_back(bytes.data() + i); - auto& mask = atp.merkle_tree_mask[f]; int const full_size = merkle_num_nodes( merkle_num_leafs(fs.file_num_blocks(f))); int const num_pieces = fs.file_num_pieces(f); int const piece_layer_size = merkle_num_leafs(num_pieces); + + if (!layer.empty()) + { + sha256_hash const computed_root = merkle_root_scratch(layer + , piece_layer_size + , pad + , scratch); + if (computed_root != fs.root(f)) + aux::throw_ex(errors::torrent_invalid_piece_layer); + } + + auto& mask = atp.merkle_tree_mask[f]; mask.resize(std::size_t(full_size), false); for (int i = merkle_first_leaf(piece_layer_size) , end = i + num_pieces; i < end; ++i) diff --git a/3rd/libtorrent-rasterbar/src/magnet_uri.cpp b/3rd/libtorrent-rasterbar/src/magnet_uri.cpp index 088394dc..40029b3c 100644 --- a/3rd/libtorrent-rasterbar/src/magnet_uri.cpp +++ b/3rd/libtorrent-rasterbar/src/magnet_uri.cpp @@ -346,6 +346,11 @@ namespace libtorrent { std::string tracker = unescape_string(value, e); if (!e && !tracker.empty()) { +#if TORRENT_USE_I2P + if (!(p.flags & torrent_flags::i2p_torrent) && is_i2p_url(tracker)) + p.flags |= torrent_flags::i2p_torrent; +#endif + p.trackers.push_back(std::move(tracker)); p.tracker_tiers.push_back(tier++); } diff --git a/3rd/libtorrent-rasterbar/src/merkle_tree.cpp b/3rd/libtorrent-rasterbar/src/merkle_tree.cpp index 6f7c00f6..0fc8afe4 100644 --- a/3rd/libtorrent-rasterbar/src/merkle_tree.cpp +++ b/3rd/libtorrent-rasterbar/src/merkle_tree.cpp @@ -59,13 +59,12 @@ namespace aux { void merkle_tree::load_verified_bits(std::vector const& verified) { - TORRENT_ASSERT(int(verified.size()) <= m_num_blocks); TORRENT_ASSERT(m_block_verified.size() == m_num_blocks); // The verified bitfield may be invalid. If so, correct it to // maintain the invariant of this class int block_index = block_layer_start(); - for (int i = 0; i < int(verified.size()); ++i) + for (int i = 0; i < std::min(int(verified.size()), m_num_blocks); ++i) { if (verified[std::size_t(i)] && has_node(block_index)) m_block_verified.set_bit(i); @@ -486,7 +485,9 @@ namespace { std::tuple merkle_tree::set_block(int const block_index , sha256_hash const& h) { +#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS INVARIANT_CHECK; +#endif TORRENT_ASSERT(block_index < m_num_blocks); auto const num_leafs = merkle_num_leafs(m_num_blocks); @@ -527,27 +528,12 @@ namespace { if (root != m_tree[root_index]) { - int const first_piece_idx = piece_layer_start(); // hash failure, clear all the internal nodes - // not the block hashes though, except for the one we just added - if (root_index >= first_piece_idx) - { - // the whole piece failed the hash check. Clear all block hashes - // in this piece and report a hash failure - merkle_clear_tree(m_tree, leafs_size, first_leaf + leafs_start); - m_tree[root_index] = root; - return std::make_tuple(set_block_result::hash_failed, leafs_start, leafs_size); - } - else - { - // in this case, the root that we validated these hashes against - // were above the piece layer, so we don't really know whether - // this piece is invalid, or some other piece. So, just clear - // the internal nodes - merkle_clear_tree(m_tree, leafs_size / 2, merkle_get_parent(first_leaf + leafs_start)); - m_tree[root_index] = root; - return std::make_tuple(set_block_result::unknown, leafs_start, leafs_size); - } + // the whole piece failed the hash check. Clear all block hashes + // in this piece and report a hash failure + merkle_clear_tree(m_tree, leafs_size, first_leaf + leafs_start); + m_tree[root_index] = root; + return std::make_tuple(set_block_result::hash_failed, leafs_start, leafs_size); } // TODO: this could be done more efficiently if bitfield had a function @@ -861,8 +847,10 @@ namespace { void merkle_tree::allocate_full() { - INVARIANT_CHECK; if (m_mode == mode_t::full_tree) return; + + INVARIANT_CHECK; + // if we already have the complete tree, we shouldn't be allocating it // again. TORRENT_ASSERT(m_mode != mode_t::block_layer); diff --git a/3rd/libtorrent-rasterbar/src/mmap_storage.cpp b/3rd/libtorrent-rasterbar/src/mmap_storage.cpp index 3dc1ccbc..ff9cf631 100644 --- a/3rd/libtorrent-rasterbar/src/mmap_storage.cpp +++ b/3rd/libtorrent-rasterbar/src/mmap_storage.cpp @@ -70,7 +70,7 @@ namespace libtorrent { namespace { -error_code translate_error(std::system_error const& err, bool const write) +error_code translate_error(std::error_code const& err, bool const write) { // We don't really know why we failed to read or write. SIGBUS essentially // means I/O failure. We assume that if we were writing, the failure was @@ -78,10 +78,10 @@ error_code translate_error(std::system_error const& err, bool const write) if (write) { #ifdef TORRENT_WINDOWS - if (err.code() == std::error_code(sig::seh_errors::in_page_error)) + if (err == std::error_code(sig::seh_errors::in_page_error)) return error_code(boost::system::errc::no_space_on_device, generic_category()); #else - if (err.code() == std::error_code(sig::errors::bus)) + if (err == std::error_code(sig::errors::bus)) return error_code(boost::system::errc::no_space_on_device, generic_category()); #endif } @@ -89,14 +89,14 @@ error_code translate_error(std::system_error const& err, bool const write) #if BOOST_VERSION >= 107700 #ifdef TORRENT_WINDOWS - if (err.code() == std::error_code(sig::seh_errors::in_page_error)) + if (err == std::error_code(sig::seh_errors::in_page_error)) return error_code(boost::system::errc::io_error, generic_category()); #else - if (err.code() == std::error_code(sig::errors::bus)) + if (err == std::error_code(sig::errors::bus)) return error_code(boost::system::errc::io_error, generic_category()); #endif - return err.code(); + return err; #else return error_code(boost::system::errc::io_error, generic_category()); @@ -180,7 +180,7 @@ error_code translate_error(std::system_error const& err, bool const write) { lt::error_code err; aux::pwrite_all(f->fd(), buf, file_offset, err); - if (err) throw std::system_error(err); + if (err) throw lt::system_error(err); return; } @@ -204,7 +204,14 @@ error_code translate_error(std::system_error const& err, bool const write) { ec.file(i); ec.operation = operation_t::partfile_write; - ec.ec = translate_error(err, true); + ec.ec = translate_error(err.code(), true); + return; + } + catch (lt::system_error const& err) + { + ec.file(i); + ec.operation = operation_t::partfile_write; + ec.ec = err.code(); return; } } @@ -589,7 +596,7 @@ error_code translate_error(std::system_error const& err, bool const write) } catch (std::system_error const& err) { - ec.ec = translate_error(err, false); + ec.ec = translate_error(err.code(), false); return -1; } @@ -676,7 +683,7 @@ error_code translate_error(std::system_error const& err, bool const write) } catch (std::system_error const& err) { - ec.ec = translate_error(err, true); + ec.ec = translate_error(err.code(), true); return -1; } diff --git a/3rd/libtorrent-rasterbar/src/peer_connection.cpp b/3rd/libtorrent-rasterbar/src/peer_connection.cpp index edec81ed..839e196e 100644 --- a/3rd/libtorrent-rasterbar/src/peer_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/peer_connection.cpp @@ -156,6 +156,7 @@ namespace libtorrent { , m_upload_only(false) , m_bitfield_received(false) , m_no_download(false) + , m_deferred_send_block_requests(false) , m_holepunch_mode(false) , m_peer_choked(true) , m_have_all(false) @@ -1184,6 +1185,22 @@ namespace libtorrent { t->received_synack(ipv6); } +#if TORRENT_USE_I2P + std::string const& peer_connection::destination() const + { + static std::string const empty; + auto s = boost::get(&m_socket); + return s ? s->destination() : empty; + } + + std::string const& peer_connection::local_i2p_endpoint() const + { + static std::string const empty; + auto s = boost::get(&m_socket); + return s ? s->local_i2p_endpoint() : empty; + } +#endif + typed_bitfield const& peer_connection::get_bitfield() const { TORRENT_ASSERT(is_single_thread()); @@ -1334,8 +1351,8 @@ namespace libtorrent { } #if TORRENT_USE_I2P - auto* i2ps = boost::get(&m_socket); - if (!i2ps && t->torrent_file().is_i2p() + if (!aux::is_i2p(m_socket) + && t->is_i2p() && !m_settings.get_bool(settings_pack::allow_i2p_mixed)) { // the torrent is an i2p torrent, the peer is a regular peer @@ -2230,7 +2247,7 @@ namespace libtorrent { m_have_piece = bits; m_num_pieces = bits.count(); t->set_seed(m_peer_info, m_num_pieces == bits.size()); - TORRENT_ASSERT(is_seed() == (m_num_pieces == bits.size())); + TORRENT_ASSERT(!t->valid_metadata() || (is_seed() == (m_num_pieces == bits.size()))); #if TORRENT_USE_INVARIANT_CHECKS if (t && t->has_picker()) @@ -3979,6 +3996,25 @@ namespace libtorrent { } void peer_connection::send_block_requests() + { + if (m_deferred_send_block_requests) return; + + std::weak_ptr weak_self = shared_from_this(); + defer(m_ios, [weak_self]() + { + std::shared_ptr p = weak_self.lock(); + if (!p) return; + + if (!p->m_deferred_send_block_requests) + return; + + p->m_deferred_send_block_requests = false; + p->send_block_requests_impl(); + }); + m_deferred_send_block_requests = true; + } + + void peer_connection::send_block_requests_impl() { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; @@ -4051,7 +4087,7 @@ namespace libtorrent { // blocks that are in the same piece into larger requests if (m_request_large_blocks) { - int const blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); + int const blocks_per_piece = t->torrent_file().blocks_per_piece(); while (!m_request_queue.empty()) { @@ -4182,7 +4218,7 @@ namespace libtorrent { // we can't touch m_connections here, since we're likely looping // over it. So defer the actual reconnection to after we've handled // the existing message queue - post(m_ses.get_context(), [weak_t, weak_self]() + post(m_ios, [weak_t, weak_self]() { std::shared_ptr tor = weak_t.lock(); std::shared_ptr p = weak_self.lock(); @@ -4553,7 +4589,6 @@ namespace libtorrent { p.payload_down_speed = statistics().download_payload_rate(); p.payload_up_speed = statistics().upload_payload_rate(); p.pid = pid(); - p.ip = remote(); p.pending_disk_bytes = m_outstanding_writing_bytes; p.pending_disk_read_bytes = m_reading_bytes; p.send_quota = m_quota[upload_channel]; @@ -4613,6 +4648,15 @@ namespace libtorrent { p.flags = {}; get_specific_peer_info(p); +#if TORRENT_USE_I2P + if (!(p.flags & peer_info::i2p_socket)) +#endif + { + p.ip = remote(); + error_code ec; + p.local_endpoint = get_socket().local_endpoint(ec); + } + if (m_snubbed) p.flags |= peer_info::snubbed; if (upload_only()) p.flags |= peer_info::upload_only; if (m_endgame_mode) p.flags |= peer_info::endgame_mode; @@ -4663,8 +4707,6 @@ namespace libtorrent { p.progress_ppm = int(std::int64_t(p.pieces.count()) * 1000000 / p.pieces.size()); } - error_code ec; - p.local_endpoint = get_socket().local_endpoint(ec); } #ifndef TORRENT_DISABLE_SUPERSEEDING @@ -5180,7 +5222,7 @@ namespace libtorrent { // the block we just picked (potentially) // hasn't been put in m_download_queue yet. // it's in m_request_queue and will be sent - // once send_block_requests() is called. + // once send_block_requests_impl() is called. m_desired_queue_size = 1; @@ -5491,7 +5533,7 @@ namespace libtorrent { case set_block_hash_result::success: { t->need_picker(); - int const blocks_per_piece = t->torrent_file().files().piece_length() / default_block_size; + int const blocks_per_piece = t->torrent_file().files().blocks_per_piece(); for (piece_index_t verified_piece = int(r.piece) + result.first_verified_block / blocks_per_piece , end = int(verified_piece) + (result.num_verified + blocks_per_piece - 1) / blocks_per_piece ; verified_piece < end; ++verified_piece) @@ -6206,6 +6248,12 @@ namespace libtorrent { m_channel_state[download_channel] &= ~peer_info::bw_network; setup_receive(); + + if (m_deferred_send_block_requests) + { + m_deferred_send_block_requests = false; + send_block_requests_impl(); + } } bool peer_connection::can_write() const @@ -6359,8 +6407,15 @@ namespace libtorrent { #endif on_connected(); - setup_send(); + + if (m_deferred_send_block_requests) + { + m_deferred_send_block_requests = false; + send_block_requests_impl(); + } + setup_receive(); + setup_send(); } // -------------------------- @@ -6527,7 +6582,16 @@ namespace libtorrent { } TORRENT_ASSERT(m_outstanding_bytes >= 0); - if (t && t->valid_metadata() && !m_disconnecting) + if (t + && t->valid_metadata() + && !m_disconnecting +#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS + // if our download queue is too long, this invariant + // check is somewhat expensive. Don't run it unless we + // opted-in to expensive invariant checks + && m_download_queue.size() <= 128 +#endif + ) { torrent_info const& ti = t->torrent_file(); // if the piece is fully downloaded, we might have popped it from the @@ -6577,12 +6641,21 @@ namespace libtorrent { TORRENT_ASSERT(r.start >= 0); } - std::set unique; - std::transform(m_download_queue.begin(), m_download_queue.end() - , std::inserter(unique, unique.begin()), std::bind(&pending_block::block, _1)); - std::transform(m_request_queue.begin(), m_request_queue.end() - , std::inserter(unique, unique.begin()), std::bind(&pending_block::block, _1)); - TORRENT_ASSERT(unique.size() == m_download_queue.size() + m_request_queue.size()); +#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS + // it's somewhat expensive to perform the uniqueness check, + // only do it for small queues, or if we've opted-in to + // expensive invariant checks + if (m_download_queue.size() + m_request_queue.size() <= 200) +#endif + { + std::set unique; + std::transform(m_download_queue.begin(), m_download_queue.end() + , std::inserter(unique, unique.begin()), std::bind(&pending_block::block, _1)); + std::transform(m_request_queue.begin(), m_request_queue.end() + , std::inserter(unique, unique.begin()), std::bind(&pending_block::block, _1)); + TORRENT_ASSERT(unique.size() == m_download_queue.size() + m_request_queue.size()); + } + if (m_peer_info) { TORRENT_ASSERT(m_peer_info->prev_amount_upload == 0); @@ -6720,8 +6793,7 @@ namespace libtorrent { { piece_picker& p = t->picker(); const std::vector& dlq = p.get_download_queue(); - const int blocks_per_piece = static_cast( - t->torrent_file().piece_length() / t->block_size()); + const int blocks_per_piece = static_cast(t->torrent_file().blocks_per_piece()); for (std::vector::const_iterator i = dlq.begin(); i != dlq.end(); ++i) diff --git a/3rd/libtorrent-rasterbar/src/peer_info.cpp b/3rd/libtorrent-rasterbar/src/peer_info.cpp index 4cd58eda..1a67deb3 100644 --- a/3rd/libtorrent-rasterbar/src/peer_info.cpp +++ b/3rd/libtorrent-rasterbar/src/peer_info.cpp @@ -86,4 +86,27 @@ namespace libtorrent { constexpr connection_type_t peer_info::standard_bittorrent; constexpr connection_type_t peer_info::web_seed; constexpr connection_type_t peer_info::http_seed; + +#if TORRENT_USE_I2P + sha256_hash peer_info::i2p_destination() const + { + sha256_hash ret; + if (!(flags & i2p_socket)) return ret; + + char const* destination = reinterpret_cast(&ip); + static_assert(sizeof(tcp::endpoint) * 2 >= sizeof(sha256_hash), "tcp::endpoint is smaller than expected"); + + std::memcpy(ret.data(), destination, ret.size()); + return ret; + } + + void peer_info::set_i2p_destination(sha256_hash dest) + { + flags |= i2p_socket; + char* destination = reinterpret_cast(&ip); + static_assert(sizeof(tcp::endpoint) * 2 >= sizeof(sha256_hash), "tcp::endpoint is smaller than expected"); + + std::memcpy(destination, dest.data(), dest.size()); + } +#endif } diff --git a/3rd/libtorrent-rasterbar/src/peer_list.cpp b/3rd/libtorrent-rasterbar/src/peer_list.cpp index a4e7f461..2fbc4ddf 100644 --- a/3rd/libtorrent-rasterbar/src/peer_list.cpp +++ b/3rd/libtorrent-rasterbar/src/peer_list.cpp @@ -245,7 +245,7 @@ namespace libtorrent { // from the peer list. Any references to these peers must be cleared // immediately after this call returns. For instance, in the piece picker. void peer_list::apply_port_filter(port_filter const& filter - , torrent_state* state, std::vector
        & banned) + , torrent_state* state, std::vector& banned) { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; @@ -275,7 +275,7 @@ namespace libtorrent { int count = int(m_peers.size()); peer_connection_interface* p = (*i)->connection; - banned.push_back(p->remote().address()); + banned.push_back(p->remote()); p->disconnect(errors::banned_by_port_filter, operation_t::bittorrent); // what *i refers to has changed, i.e. cur was deleted @@ -301,9 +301,10 @@ namespace libtorrent { TORRENT_ASSERT(p->in_use); TORRENT_ASSERT(m_locked_peer != p); - auto const addr = p->address(); - auto const range = find_peers(addr); - auto const iter = std::find_if(range.first, range.second, match_peer_endpoint(addr, p->port)); + auto const range = std::equal_range(m_peers.begin(), m_peers.end(), p, peer_address_compare{}); + auto const iter = std::find_if(range.first, range.second, [&](torrent_peer const* needle) { + return torrent_peer_equal(needle, p); + }); if (iter == range.second) return; erase_peer(iter, state); } @@ -613,8 +614,15 @@ namespace libtorrent { iterator iter; torrent_peer* i = nullptr; +#if TORRENT_USE_I2P + std::string const i2p_dest = c.destination(); +#else + std::string const i2p_dest; +#endif + bool found = false; - if (state->allow_multiple_connections_per_ip) + // this check doesn't support i2p peers + if (state->allow_multiple_connections_per_ip && i2p_dest.empty()) { auto const& remote = c.remote(); auto const addr = remote.address(); @@ -629,15 +637,33 @@ namespace libtorrent { } else { - iter = std::lower_bound( - m_peers.begin(), m_peers.end() - , c.remote().address(), peer_address_compare() - ); +#if TORRENT_USE_I2P + if (!i2p_dest.empty()) + { + iter = std::lower_bound( + m_peers.begin(), m_peers.end() + , i2p_dest, peer_address_compare() + ); - if (iter != m_peers.end() && (*iter)->address() == c.remote().address()) + if (iter != m_peers.end() && (*iter)->is_i2p_addr && (*iter)->dest() == i2p_dest) + { + TORRENT_ASSERT((*iter)->in_use); + found = true; + } + } + else +#endif { - TORRENT_ASSERT((*iter)->in_use); - found = true; + iter = std::lower_bound( + m_peers.begin(), m_peers.end() + , c.remote().address(), peer_address_compare() + ); + + if (iter != m_peers.end() && (*iter)->address() == c.remote().address()) + { + TORRENT_ASSERT((*iter)->in_use); + found = true; + } } } @@ -658,9 +684,19 @@ namespace libtorrent { #ifndef TORRENT_DISABLE_LOGGING if (i->connection != nullptr && c.should_log(peer_log_alert::info)) { - c.peer_log(peer_log_alert::info, "DUPLICATE PEER", "this: \"%s\" that: \"%s\"" - , print_address(c.remote().address()).c_str() - , print_address(i->address()).c_str()); +#if TORRENT_USE_I2P + if (!i2p_dest.empty()) + { + c.peer_log(peer_log_alert::info, "DUPLICATE PEER", "destination: \"%s\"" + , i2p_dest.c_str()); + } + else +#endif + { + c.peer_log(peer_log_alert::info, "DUPLICATE PEER", "this: \"%s\" that: \"%s\"" + , print_address(c.remote().address()).c_str() + , print_address(i->address()).c_str()); + } } #endif if (i->banned) @@ -671,9 +707,18 @@ namespace libtorrent { if (i->connection != nullptr) { - bool const self_connection = - i->connection->remote() == c.local_endpoint() + bool self_connection = false; +#if TORRENT_USE_I2P + if (!i2p_dest.empty()) + { + self_connection = i->connection->local_i2p_endpoint() == i2p_dest; + } + else +#endif + { + self_connection = i->connection->remote() == c.local_endpoint() || i->connection->local_endpoint() == c.remote(); + } if (self_connection) { @@ -694,6 +739,42 @@ namespace libtorrent { c.disconnect(errors::duplicate_peer_id, operation_t::bittorrent); return false; } +#if TORRENT_USE_I2P + else if (!i2p_dest.empty()) + { + // duplicate connection resolution for i2p connections is + // simple. The smaller address takes priority for making the + // outgoing connection + + std::string const& other_dest = i->connection->destination(); + + // decide which peer connection to disconnect + // if the ports are equal, pick on at random + bool disconnect1 = c.is_outgoing() && i2p_dest > other_dest; + +#ifndef TORRENT_DISABLE_LOGGING + if (c.should_log(peer_log_alert::info)) + { + c.peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION" + , "our: %s other: %s disconnecting: %s" + , i2p_dest.c_str(), other_dest.c_str(), disconnect1 ? "yes" : "no"); + i->connection->peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION" + , "our: %s other: %s disconnecting: %s" + , other_dest.c_str(), i2p_dest.c_str(), disconnect1 ? "no" : "yes"); + } +#endif + + if (disconnect1) + { + c.disconnect(errors::duplicate_peer_id, operation_t::bittorrent); + return false; + } + TORRENT_ASSERT(m_locked_peer == nullptr); + m_locked_peer = i; + i->connection->disconnect(errors::duplicate_peer_id, operation_t::bittorrent); + m_locked_peer = nullptr; + } +#endif else { // at this point, we need to disconnect either @@ -769,24 +850,36 @@ namespace libtorrent { ); } - bool const is_v6 = lt::aux::is_v6(c.remote()); - torrent_peer* p = m_peer_allocator.allocate_peer_entry( - is_v6 ? torrent_peer_allocator_interface::ipv6_peer_type - : torrent_peer_allocator_interface::ipv4_peer_type); - if (p == nullptr) return false; - - if (is_v6) - p = new (p) ipv6_peer(c.remote(), false, {}); +#if TORRENT_USE_I2P + if (!i2p_dest.empty()) + { + i = add_i2p_peer(i2p_dest, peer_info::incoming, {}, state); + // we're about to attach the new connection to this torrent_peer + if (is_connect_candidate(*i)) + update_connect_candidates(-1); + } else - p = new (p) ipv4_peer(c.remote(), false, {}); +#endif + { + bool const is_v6 = lt::aux::is_v6(c.remote()); + torrent_peer* p = m_peer_allocator.allocate_peer_entry( + is_v6 ? torrent_peer_allocator_interface::ipv6_peer_type + : torrent_peer_allocator_interface::ipv4_peer_type); + if (p == nullptr) return false; + + if (is_v6) + p = new (p) ipv6_peer(c.remote(), false, {}); + else + p = new (p) ipv4_peer(c.remote(), false, {}); - iter = m_peers.insert(iter, p); + iter = m_peers.insert(iter, p); - if (m_round_robin >= iter - m_peers.begin()) ++m_round_robin; + if (m_round_robin >= iter - m_peers.begin()) ++m_round_robin; - i = *iter; + i = *iter; - i->source = static_cast(peer_info::incoming); + i->source = static_cast(peer_info::incoming); + } } TORRENT_ASSERT(i); @@ -817,6 +910,10 @@ namespace libtorrent { INVARIANT_CHECK; +#if TORRENT_USE_I2P + if (p->is_i2p_addr) return true; +#endif + if (p->port == port) return true; if (state->allow_multiple_connections_per_ip) @@ -857,13 +954,8 @@ namespace libtorrent { #if TORRENT_USE_ASSERTS else { -#if TORRENT_USE_I2P - if (!p->is_i2p_addr) -#endif - { - std::pair range = find_peers(p->address()); - TORRENT_ASSERT(std::distance(range.first, range.second) == 1); - } + std::pair range = find_peers(p->address()); + TORRENT_ASSERT(std::distance(range.first, range.second) == 1); } #endif @@ -1062,7 +1154,7 @@ namespace libtorrent { auto const remote_address = remote.address(); // just ignore the obviously invalid entries - if (remote_address == address() || remote.port() == 0) + if (remote_address == address() || remote.port() == 0 || remote.port() == 1) return nullptr; // don't allow link-local IPv6 addresses since they diff --git a/3rd/libtorrent-rasterbar/src/posix_disk_io.cpp b/3rd/libtorrent-rasterbar/src/posix_disk_io.cpp index 492ac2f1..c597f82c 100644 --- a/3rd/libtorrent-rasterbar/src/posix_disk_io.cpp +++ b/3rd/libtorrent-rasterbar/src/posix_disk_io.cpp @@ -105,7 +105,7 @@ namespace { { error.ec = errors::no_memory; error.operation = operation_t::alloc_cache_piece; - post(m_ios, [=, h = std::move(handler)]{ h(disk_buffer_holder(m_buffer_pool, nullptr, 0), error); }); + post(m_ios, [this, error, h = std::move(handler)]{ h(disk_buffer_holder(m_buffer_pool, nullptr, 0), error); }); return; } diff --git a/3rd/libtorrent-rasterbar/src/read_resume_data.cpp b/3rd/libtorrent-rasterbar/src/read_resume_data.cpp index 19583ffc..eff654a9 100644 --- a/3rd/libtorrent-rasterbar/src/read_resume_data.cpp +++ b/3rd/libtorrent-rasterbar/src/read_resume_data.cpp @@ -90,6 +90,14 @@ namespace { return ret; } + std::int64_t const file_version = rd.dict_find_int_value("file-version", 1); + + if (file_version != 1 && file_version != 2) + { + ec = errors::invalid_file_tag; + return ret; + } + auto info_hash = rd.dict_find_string_value("info-hash"); auto info_hash2 = rd.dict_find_string_value("info-hash2"); if (info_hash.size() != std::size_t(sha1_hash::size()) @@ -164,20 +172,54 @@ namespace { ret.merkle_trees.back().emplace_back(hashes); } - auto const verified = de.dict_find_string_value("verified"); - ret.verified_leaf_hashes.emplace_back(verified.size(), false); - for (std::size_t j = 0; j < verified.size(); ++j) + if (bdecode_node const verified = de.dict_find_string("verified")) { - if (verified[j] == '1') - ret.verified_leaf_hashes.back()[j] = true; + string_view const str = verified.string_value(); + if (file_version == 1) + { + ret.verified_leaf_hashes.emplace_back(str.size()); + auto& v = ret.verified_leaf_hashes.back(); + for (std::size_t j = 0; j < str.size(); ++j) + { + if (str[j] == '1') + v[j] = true; + } + } + else + { + ret.verified_leaf_hashes.emplace_back(str.size() * 8); + auto& v = ret.verified_leaf_hashes.back(); + for (std::size_t j = 0; j < v.size(); ++j) + { + if (str[j / 8] & (0x80 >> (j % 8))) + v[j] = true; + } + } } - auto const mask = de.dict_find_string_value("mask"); - ret.merkle_tree_mask.emplace_back(mask.size(), false); - for (std::size_t j = 0; j < mask.size(); ++j) + if (bdecode_node const mask = de.dict_find_string("mask")) { - if (mask[j] == '1') - ret.merkle_tree_mask.back()[j] = true; + string_view const str = mask.string_value(); + if (file_version == 1) + { + ret.merkle_tree_mask.emplace_back(str.size()); + auto& m = ret.merkle_tree_mask.back(); + for (std::size_t j = 0; j < str.size(); ++j) + { + if (str[j] == '1') + m[j] = true; + } + } + else + { + ret.merkle_tree_mask.emplace_back(str.size() * 8); + auto& m = ret.merkle_tree_mask.back(); + for (std::size_t j = 0; j < m.size(); ++j) + { + if (str[j / 8] & (0x80 >> (j % 8))) + m[j] = true; + } + } } } } @@ -216,6 +258,9 @@ namespace { apply_flag(ret.flags, rd, "auto_managed", torrent_flags::auto_managed); #ifndef TORRENT_DISABLE_SUPERSEEDING apply_flag(ret.flags, rd, "super_seeding", torrent_flags::super_seeding); +#endif +#if TORRENT_USE_I2P + apply_flag(ret.flags, rd, "i2p", torrent_flags::i2p_torrent); #endif apply_flag(ret.flags, rd, "sequential_download", torrent_flags::sequential_download); apply_flag(ret.flags, rd, "stop_when_ready", torrent_flags::stop_when_ready); @@ -288,6 +333,9 @@ namespace { { ret.trackers.push_back(tier_list.list_string_value_at(j).to_string()); ret.tracker_tiers.push_back(tier); +#if TORRENT_USE_I2P + if (is_i2p_url(ret.trackers.back())) ret.flags |= torrent_flags::i2p_torrent; +#endif } ++tier; } @@ -329,22 +377,45 @@ namespace { // some sanity checking. Maybe we shouldn't be in seed mode anymore if (bdecode_node const pieces = rd.dict_find_string("pieces")) { - char const* pieces_str = pieces.string_ptr(); - int const pieces_len = pieces.string_length(); - ret.have_pieces.resize(pieces_len); - ret.verified_pieces.resize(pieces_len); - for (piece_index_t i(0); i < ret.verified_pieces.end_index(); ++i) + if (file_version == 1) { - // being in seed mode and missing a piece is not compatible. - // Leave seed mode if that happens - if (pieces_str[static_cast(i)] & 1) ret.have_pieces.set_bit(i); - else ret.have_pieces.clear_bit(i); - - if (pieces_str[static_cast(i)] & 2) ret.verified_pieces.set_bit(i); - else ret.verified_pieces.clear_bit(i); + char const* pieces_str = pieces.string_ptr(); + int const pieces_len = pieces.string_length(); + ret.have_pieces.resize(pieces_len); + ret.verified_pieces.resize(pieces_len); + bool any_verified = false; + for (piece_index_t i(0); i < ret.verified_pieces.end_index(); ++i) + { + // being in seed mode and missing a piece is not compatible. + // Leave seed mode if that happens + if (pieces_str[static_cast(i)] & 1) ret.have_pieces.set_bit(i); + else ret.have_pieces.clear_bit(i); + + if (pieces_str[static_cast(i)] & 2) + { + ret.verified_pieces.set_bit(i); + any_verified = true; + } + else + { + ret.verified_pieces.clear_bit(i); + } + } + if (!any_verified) ret.verified_pieces.clear(); + } + else if (file_version == 2) + { + string_view const str = pieces.string_value(); + ret.have_pieces.assign(str.data(), int(str.size()) * 8); } } + if (bdecode_node const verified = rd.dict_find_string("verified")) + { + string_view const str = verified.string_value(); + ret.verified_pieces.assign(str.data(), int(str.size()) * 8); + } + if (bdecode_node const piece_priority = rd.dict_find_string("piece_priority")) { char const* prio_str = piece_priority.string_ptr(); diff --git a/3rd/libtorrent-rasterbar/src/request_blocks.cpp b/3rd/libtorrent-rasterbar/src/request_blocks.cpp index e18f89c9..4aa78cf1 100644 --- a/3rd/libtorrent-rasterbar/src/request_blocks.cpp +++ b/3rd/libtorrent-rasterbar/src/request_blocks.cpp @@ -141,10 +141,6 @@ namespace libtorrent { // the number of blocks we want, but it will try to make the picked // blocks be from whole pieces, possibly by returning more blocks // than we requested. -#if TORRENT_USE_ASSERTS - error_code ec; - TORRENT_ASSERT(c.remote() == c.get_socket().remote_endpoint(ec) || ec); -#endif aux::session_interface& ses = t.session(); diff --git a/3rd/libtorrent-rasterbar/src/resolver.cpp b/3rd/libtorrent-rasterbar/src/resolver.cpp index 796ffb50..33096ad5 100644 --- a/3rd/libtorrent-rasterbar/src/resolver.cpp +++ b/3rd/libtorrent-rasterbar/src/resolver.cpp @@ -66,6 +66,25 @@ namespace aux { COMPLETE_ASYNC("resolver::on_lookup"); if (ec) { + failed_dns_cache_entry& ce = m_failed_cache[hostname]; + ce.last_seen = time_now(); + ce.error = ec; + + // if the cache grows too big, weed out the + // oldest entries + if (int(m_failed_cache.size()) > m_max_size) + { + auto oldest = m_failed_cache.begin(); + for (auto k = m_failed_cache.begin(); k != m_failed_cache.end(); ++k) + { + if (k->second.last_seen < oldest->second.last_seen) + oldest = k; + } + + // remove the oldest entry + m_failed_cache.erase(oldest); + } + auto const range = m_callbacks.equal_range(hostname); for (auto c = range.first; c != range.second; ++c) callback(std::move(c->second), ec, {}); @@ -73,6 +92,12 @@ namespace aux { return; } + { + auto const k = m_failed_cache.find(hostname); + if (k != m_failed_cache.end()) + m_failed_cache.erase(k); + } + dns_cache_entry& ce = m_cache[hostname]; ce.last_seen = time_now(); ce.addresses.clear(); @@ -109,7 +134,7 @@ namespace aux { address const ip = make_address(host, ec); if (!ec) { - post(m_ios, [=]{ callback(h, ec, std::vector
        {ip}); }); + post(m_ios, [this, h, ec, ip]{ callback(h, ec, std::vector
        {ip}); }); return; } ec.clear(); @@ -122,7 +147,20 @@ namespace aux { || i->second.last_seen + m_timeout >= time_now()) { std::vector
        ips = i->second.addresses; - post(m_ios, [=] { callback(h, ec, ips); }); + post(m_ios, [this, h, ec, ips] { callback(h, ec, ips); }); + return; + } + } + + auto const k = m_failed_cache.find(host); + if (k != m_failed_cache.end()) + { + // keep cache entries valid for m_timeout seconds + if ((flags & resolver_interface::cache_only) + || k->second.last_seen + m_timeout >= time_now()) + { + error_code error_code = k->second.error; + post(m_ios, [this, h, error_code] { callback(h, error_code, {}); }); return; } } @@ -130,7 +168,7 @@ namespace aux { if (flags & resolver_interface::cache_only) { // we did not find a cache entry, fail the lookup - post(m_ios, [=] { + post(m_ios, [this, h] { callback(h, boost::asio::error::host_not_found, std::vector
        {}); }); return; diff --git a/3rd/libtorrent-rasterbar/src/session_impl.cpp b/3rd/libtorrent-rasterbar/src/session_impl.cpp index 8416bf90..9b6bf96a 100644 --- a/3rd/libtorrent-rasterbar/src/session_impl.cpp +++ b/3rd/libtorrent-rasterbar/src/session_impl.cpp @@ -567,6 +567,9 @@ bool ssl_server_name_callback(ssl::stream_handle_type stream_handle, std::string , m_close_file_timer(m_io_context) , m_paused(flags & session::paused) { +#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS + validate_settings(); +#endif } template @@ -1093,7 +1096,6 @@ bool ssl_server_name_callback(ssl::stream_handle_type stream_handle, std::string m_i2p_listen_socket->close(ec); TORRENT_ASSERT(!ec); } - m_i2p_listen_socket.reset(); #endif #ifndef TORRENT_DISABLE_LOGGING @@ -1191,10 +1193,8 @@ bool ssl_server_name_callback(ssl::stream_handle_type stream_handle, std::string void session_impl::set_port_filter(port_filter const& f) { m_port_filter = f; - if (m_settings.get_bool(settings_pack::no_connect_privileged_ports)) - m_port_filter.add_rule(0, 1024, port_filter::blocked); // Close connections whose endpoint is filtered - // by the new ip-filter + // by the new port-filter for (auto const& t : m_torrents) t->port_filter_updated(); } @@ -1299,18 +1299,21 @@ namespace { req.ssl_ctx = &m_ssl_ctx; #endif - TORRENT_ASSERT(req.outgoing_socket); - auto ls = req.outgoing_socket.get(); - - req.listen_port = -#if TORRENT_USE_I2P - (req.kind == tracker_request::i2p) ? 1 : -#endif + auto ls = req.outgoing_socket.get(); + if (ls) + { + req.listen_port = #ifdef TORRENT_SSL_PEERS // SSL torrents use the SSL listen port use_ssl ? make_announce_port(ssl_listen_port(ls)) : #endif make_announce_port(listen_port(ls)); + } + else + { + TORRENT_ASSERT(req.kind == tracker_request::i2p); + req.listen_port = 1; + } m_tracker_manager.queue_request(get_context(), std::move(req), m_settings, c); } @@ -1519,6 +1522,34 @@ namespace { } } +#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS + void session_impl::validate_setting(int const int_name, int const min, int const max) + { + int const val = m_settings.get_int(int_name); + TORRENT_ASSERT_PRECOND_MSG(val >= min, name_for_setting(int_name)); + TORRENT_ASSERT_PRECOND_MSG(val <= max, name_for_setting(int_name)); +#ifndef TORRENT_DISABLE_LOGGING + if (val < min || val > max) + session_log("invalid %s setting: %d", name_for_setting(int_name), val); +#endif + } + + void session_impl::validate_settings() + { + validate_setting(settings_pack::out_enc_policy, 0, 2); + validate_setting(settings_pack::in_enc_policy, 0, 2); + validate_setting(settings_pack::allowed_enc_level, 1, 3); + validate_setting(settings_pack::mixed_mode_algorithm, 0, 1); + validate_setting(settings_pack::proxy_type, 0, 5); + validate_setting(settings_pack::disk_io_read_mode, 0, 3); + validate_setting(settings_pack::disk_io_write_mode, 0, 3); + validate_setting(settings_pack::choking_algorithm, 0, 3); + validate_setting(settings_pack::seed_choking_algorithm, 0, 3); + validate_setting(settings_pack::suggest_mode, 0, 1); + validate_setting(settings_pack::disk_write_mode, 0, 2); + } +#endif + void session_impl::apply_settings_pack_impl(settings_pack const& pack) { bool const reopen_listen_port @@ -1542,6 +1573,11 @@ namespace { #endif apply_pack(&pack, m_settings, this); + +#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS + validate_settings(); +#endif + m_disk_thread->settings_updated(); if (!reopen_listen_port) @@ -2331,8 +2367,16 @@ namespace { m_i2p_conn.close(ec); return; } + TORRENT_ASSERT(!m_abort); + i2p_session_options session_options{ + m_settings.get_int(settings_pack::i2p_inbound_quantity) + , m_settings.get_int(settings_pack::i2p_outbound_quantity) + , m_settings.get_int(settings_pack::i2p_inbound_length) + , m_settings.get_int(settings_pack::i2p_outbound_length) + }; m_i2p_conn.open(m_settings.get_str(settings_pack::i2p_hostname) , m_settings.get_int(settings_pack::i2p_port) + , session_options , std::bind(&session_impl::on_i2p_open, this, _1)); #endif } @@ -2354,17 +2398,6 @@ namespace { #endif #if TORRENT_USE_I2P - - proxy_settings session_impl::i2p_proxy() const - { - proxy_settings ret; - - ret.hostname = m_settings.get_str(settings_pack::i2p_hostname); - ret.type = settings_pack::i2p_proxy; - ret.port = std::uint16_t(m_settings.get_int(settings_pack::i2p_port)); - return ret; - } - void session_impl::on_i2p_open(error_code const& ec) { if (ec) @@ -2386,6 +2419,7 @@ namespace { void session_impl::open_new_incoming_i2p_connection() { + if (m_abort) return; if (!m_i2p_conn.is_open()) return; if (m_i2p_listen_socket) return; @@ -2420,9 +2454,9 @@ namespace { #endif return; } - open_new_incoming_i2p_connection(); incoming_connection(std::move(*m_i2p_listen_socket)); m_i2p_listen_socket.reset(); + open_new_incoming_i2p_connection(); } #endif @@ -2469,7 +2503,12 @@ namespace { auto s = std::static_pointer_cast(si)->udp_sock; - TORRENT_ASSERT(s->sock.is_closed() || s->sock.local_endpoint().protocol() == ep.protocol()); + // the destination address family matching the local socket's address + // family does not hold for proxies that we talk to over IPv4 but can + // route to IPv6 + TORRENT_ASSERT(s->sock.is_closed() + || s->sock.get_proxy_settings().type != settings_pack::none + || s->sock.local_endpoint().protocol() == ep.protocol()); s->sock.send(ep, p, ec, flags); @@ -4882,11 +4921,11 @@ namespace { torrent_handle handle(torrent_ptr); - if (!torrent_ptr) - { - m_alerts.emplace_alert(handle, std::move(alert_params), ec); - return handle; - } + if (!torrent_ptr) + { + m_alerts.emplace_alert(handle, std::move(alert_params), ec); + return handle; + } TORRENT_ASSERT(info_hash.has_v1() || info_hash.has_v2()); @@ -4900,7 +4939,7 @@ namespace { if (!added) { abort_torrent.disarm(); - m_alerts.emplace_alert(handle, std::move(alert_params), ec); + m_alerts.emplace_alert(handle, std::move(alert_params), ec); return handle; } @@ -5126,12 +5165,16 @@ namespace { std::shared_ptr match; for (auto& ls : m_listen_sockets) { - if (is_v4(ls->local_endpoint) != remote_address.is_v4()) continue; + // this is almost, but not quite, like can_route() + if (!(ls->flags & listen_socket_t::proxy) + && is_v4(ls->local_endpoint) != remote_address.is_v4()) + continue; if (ls->ssl != ssl) continue; if (!(ls->flags & listen_socket_t::local_network)) with_gateways.push_back(ls); - if (match_addr_mask(ls->local_endpoint.address(), remote_address, ls->netmask)) + if (ls->flags & listen_socket_t::proxy + || match_addr_mask(ls->local_endpoint.address(), remote_address, ls->netmask)) { // is this better than the previous match? match = ls; @@ -5235,9 +5278,7 @@ namespace { std::shared_ptr tptr = h.m_torrent.lock(); if (!tptr) return; - - m_alerts.emplace_alert(tptr->get_handle() - , tptr->info_hash(), tptr->get_userdata()); + if (!tptr->is_added()) return; remove_torrent_impl(tptr, options); @@ -5343,16 +5384,10 @@ namespace { { if (m_settings.get_bool(settings_pack::no_connect_privileged_ports)) { - m_port_filter.add_rule(0, 1024, port_filter::blocked); - // Close connections whose endpoint is filtered - // by the new ip-filter + // by the new setting for (auto const& t : m_torrents) - t->port_filter_updated(); - } - else - { - m_port_filter.add_rule(0, 1024, 0); + t->privileged_port_updated(); } } @@ -6210,6 +6245,7 @@ namespace { // since we're destructing the session, no more alerts will make it out to // the user. So stop posting them now m_alerts.set_alert_mask({}); + m_alerts.set_notify_function({}); // this is not allowed to be the network thread! // TORRENT_ASSERT(is_not_thread()); @@ -7097,19 +7133,25 @@ namespace { && m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker) TORRENT_ASSERT(m_stats_counters[counters::num_unchoke_slots] == std::numeric_limits::max()); - for (torrent_list_index_t l{}; l != m_torrent_lists.end_index(); ++l) +#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS + // this can get expensive when there are a lot of torrents + if (m_download_queue.size() < 500) +#endif { - std::vector const& list = m_torrent_lists[l]; - for (auto const& i : list) + for (torrent_list_index_t l{}; l != m_torrent_lists.end_index(); ++l) { - TORRENT_ASSERT(i->m_links[l].in_list()); - } + std::vector const& list = m_torrent_lists[l]; + for (auto const& i : list) + { + TORRENT_ASSERT(i->m_links[l].in_list()); + } - queue_position_t idx{}; - for (auto t : m_download_queue) - { - TORRENT_ASSERT(t->queue_position() == idx); - ++idx; + queue_position_t idx{}; + for (auto t : m_download_queue) + { + TORRENT_ASSERT(t->queue_position() == idx); + ++idx; + } } } diff --git a/3rd/libtorrent-rasterbar/src/settings_pack.cpp b/3rd/libtorrent-rasterbar/src/settings_pack.cpp index 230a9280..bf368e35 100644 --- a/3rd/libtorrent-rasterbar/src/settings_pack.cpp +++ b/3rd/libtorrent-rasterbar/src/settings_pack.cpp @@ -148,7 +148,7 @@ constexpr int DISK_WRITE_MODE = settings_pack::enable_os_cache; SET(proxy_username, "", &session_impl::update_proxy), SET(proxy_password, "", &session_impl::update_proxy), SET(i2p_hostname, "", &session_impl::update_i2p_bridge), - SET(peer_fingerprint, "-LT2080-", nullptr), + SET(peer_fingerprint, "-LT2090-", nullptr), SET(dht_bootstrap_nodes, "dht.libtorrent.org:25401", &session_impl::update_dht_bootstrap_nodes) }}); @@ -398,6 +398,10 @@ constexpr int DISK_WRITE_MODE = settings_pack::enable_os_cache; SET(metadata_token_limit, 2500000, nullptr), SET(disk_write_mode, settings_pack::mmap_write_mode_t::auto_mmap_write, nullptr), SET(mmap_file_size_cutoff, 40, nullptr), + SET(i2p_inbound_quantity, 3, nullptr), + SET(i2p_outbound_quantity, 3, nullptr), + SET(i2p_inbound_length, 3, nullptr), + SET(i2p_outbound_length, 3, nullptr) }}); #undef SET diff --git a/3rd/libtorrent-rasterbar/src/socket_type.cpp b/3rd/libtorrent-rasterbar/src/socket_type.cpp index 081cd768..bf8f3f67 100644 --- a/3rd/libtorrent-rasterbar/src/socket_type.cpp +++ b/3rd/libtorrent-rasterbar/src/socket_type.cpp @@ -99,18 +99,18 @@ namespace aux { #endif struct idx_visitor { - socket_type_t operator()(tcp::socket const&) { return socket_type_t::tcp; } - socket_type_t operator()(socks5_stream const&) { return socket_type_t::socks5; } - socket_type_t operator()(http_stream const&) { return socket_type_t::http; } - socket_type_t operator()(utp_stream const&) { return socket_type_t::utp; } + socket_type_t operator()(tcp::socket const&) const { return socket_type_t::tcp; } + socket_type_t operator()(socks5_stream const&) const { return socket_type_t::socks5; } + socket_type_t operator()(http_stream const&) const { return socket_type_t::http; } + socket_type_t operator()(utp_stream const&) const { return socket_type_t::utp; } #if TORRENT_USE_I2P - socket_type_t operator()(i2p_stream const&) { return socket_type_t::i2p; } + socket_type_t operator()(i2p_stream const&) const { return socket_type_t::i2p; } #endif #if TORRENT_USE_SSL - socket_type_t operator()(ssl_stream const&) { return socket_type_t::tcp_ssl; } - socket_type_t operator()(ssl_stream const&) { return socket_type_t::socks5_ssl; } - socket_type_t operator()(ssl_stream const&) { return socket_type_t::http_ssl; } - socket_type_t operator()(ssl_stream const&) { return socket_type_t::utp_ssl; } + socket_type_t operator()(ssl_stream const&) const { return socket_type_t::tcp_ssl; } + socket_type_t operator()(ssl_stream const&) const { return socket_type_t::socks5_ssl; } + socket_type_t operator()(ssl_stream const&) const { return socket_type_t::http_ssl; } + socket_type_t operator()(ssl_stream const&) const { return socket_type_t::utp_ssl; } #endif }; @@ -143,10 +143,10 @@ namespace aux { struct get_close_reason_visitor { #if TORRENT_USE_SSL - close_reason_t operator()(ssl_stream& s) const + close_reason_t operator()(ssl_stream const& s) const { return s.next_layer().get_close_reason(); } #endif - close_reason_t operator()(utp_stream& s) const + close_reason_t operator()(utp_stream const& s) const { return s.get_close_reason(); } template close_reason_t operator()(T const&) const { return close_reason_t::none; } diff --git a/3rd/libtorrent-rasterbar/src/time.cpp b/3rd/libtorrent-rasterbar/src/time.cpp index 156300e4..e58d52b3 100644 --- a/3rd/libtorrent-rasterbar/src/time.cpp +++ b/3rd/libtorrent-rasterbar/src/time.cpp @@ -32,9 +32,43 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/time.hpp" +#include + namespace libtorrent { namespace aux { time_point time_now() { return clock_type::now(); } time_point32 time_now32() { return time_point_cast(clock_type::now()); } + // for simplying implementation + using std::chrono::system_clock; + + + // consider using std::chrono::clock_cast on C++20 + time_t to_time_t(const time_point32 tp) + { + // special case for unset value + if (tp == time_point32(seconds32(0))) return 0; + + const auto lt_now = clock_type::now(); + const auto sys_now = system_clock::now(); + + const auto r = sys_now + std::chrono::duration_cast(tp - lt_now) + lt::milliseconds(500); + return system_clock::to_time_t(r); + } + + // consider using std::chrono::clock_cast on C++20 + time_point32 from_time_t(const std::time_t t) + { + // special case for unset value + if (t == 0) return time_point32(seconds32(0)); + + const auto tp = system_clock::from_time_t(t); + const auto sys_now = system_clock::now(); + const auto lt_now = clock_type::now(); + + auto r = lt_now + std::chrono::duration_cast(tp - sys_now); + // the conversion to seconds will truncate, make sure we round + return std::chrono::time_point_cast(r + milliseconds(500)); + } + } } diff --git a/3rd/libtorrent-rasterbar/src/torrent.cpp b/3rd/libtorrent-rasterbar/src/torrent.cpp index 52e6c1aa..e99dfc63 100644 --- a/3rd/libtorrent-rasterbar/src/torrent.cpp +++ b/3rd/libtorrent-rasterbar/src/torrent.cpp @@ -219,9 +219,9 @@ bool is_downloading_state(int const st) , m_super_seeding(p.flags & torrent_flags::super_seeding) #endif , m_stop_when_ready(p.flags & torrent_flags::stop_when_ready) - , m_need_save_resume_data(p.flags & torrent_flags::need_save_resume) , m_enable_dht(!bool(p.flags & torrent_flags::disable_dht)) , m_enable_lsd(!bool(p.flags & torrent_flags::disable_lsd)) + , m_i2p(bool(p.flags & torrent_flags::i2p_torrent)) , m_max_uploads((1 << 24) - 1) , m_num_uploads(0) , m_enable_pex(!bool(p.flags & torrent_flags::disable_pex)) @@ -233,8 +233,8 @@ bool is_downloading_state(int const st) , m_announce_to_dht(!(p.flags & torrent_flags::paused)) , m_ssl_torrent(false) , m_deleted(false) - , m_last_download(seconds32(p.last_download)) - , m_last_upload(seconds32(p.last_upload)) + , m_last_download(aux::from_time_t(p.last_download)) + , m_last_upload(aux::from_time_t(p.last_upload)) , m_userdata(p.userdata) , m_auto_managed(p.flags & torrent_flags::auto_managed) , m_current_gauge_state(static_cast(no_gauge_state)) @@ -246,6 +246,12 @@ bool is_downloading_state(int const st) , m_outstanding_file_priority(false) , m_complete_sent(false) { + if (p.flags & torrent_flags::need_save_resume) + { + m_need_save_resume_data |= torrent_handle::only_if_modified + | torrent_handle::if_metadata_changed; + } + // we cannot log in the constructor, because it relies on shared_from_this // being initialized, which happens after the constructor returns. @@ -261,6 +267,11 @@ bool is_downloading_state(int const st) if (!m_torrent_file) m_torrent_file = (p.ti ? p.ti : std::make_shared(m_info_hash)); +#if TORRENT_USE_I2P + if (m_torrent_file->is_i2p()) + m_i2p = true; +#endif + if (m_torrent_file->is_valid()) { error_code ec = initialize_merkle_trees(); @@ -514,7 +525,7 @@ bool is_downloading_state(int const st) m_verified.clear(); m_verifying.clear(); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); } void torrent::verified(piece_index_t const piece) @@ -522,6 +533,7 @@ bool is_downloading_state(int const st) TORRENT_ASSERT(!m_verified.get_bit(piece)); ++m_num_verified; m_verified.set_bit(piece); + set_need_save_resume(torrent_handle::if_download_progress); } void torrent::start() @@ -559,6 +571,11 @@ bool is_downloading_state(int const st) add_peer(peer, peer_info::resume_data); } + if (!p.peers.empty()) + { + do_connect_boost(); + } + #ifndef TORRENT_DISABLE_LOGGING if (should_log() && !p.peers.empty()) { @@ -648,7 +665,7 @@ bool is_downloading_state(int const st) inc_stats_counter(counters::non_filter_torrents); } - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); m_apply_ip_filter = b; ip_filter_updated(); @@ -669,6 +686,13 @@ bool is_downloading_state(int const st) if (!m_enable_dht) return false; if (!m_ses.announce_dht()) return false; +#if TORRENT_USE_I2P + // i2p torrents don't announced on the DHT + // unless we allow mixed swarms + if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) + return false; +#endif + if (!m_ses.dht()) return false; if (m_torrent_file->is_valid() && !m_files_checked) return false; if (!m_announce_to_dht) return false; @@ -730,7 +754,7 @@ bool is_downloading_state(int const st) { ec.assign(errors::no_metadata, libtorrent_category()); } - else if (piece < piece_index_t{0} || piece >= m_torrent_file->end_piece()) + else if (!has_piece_passed(piece)) { ec.assign(errors::invalid_piece_index, libtorrent_category()); } @@ -870,12 +894,18 @@ bool is_downloading_state(int const st) ret |= torrent_flags::disable_lsd; if (!m_enable_pex) ret |= torrent_flags::disable_pex; + if (m_i2p) + ret |= torrent_flags::i2p_torrent; return ret; } void torrent::set_flags(torrent_flags_t const flags , torrent_flags_t const mask) { + if (mask & torrent_flags::i2p_torrent) + { + m_i2p = bool(flags & torrent_flags::i2p_torrent); + } if ((mask & torrent_flags::seed_mode) && !(flags & torrent_flags::seed_mode)) { @@ -909,19 +939,19 @@ bool is_downloading_state(int const st) if (mask & torrent_flags::disable_dht) { bool const new_value = !bool(flags & torrent_flags::disable_dht); - if (m_enable_dht != new_value) set_need_save_resume(); + if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed); m_enable_dht = new_value; } if (mask & torrent_flags::disable_lsd) { bool const new_value = !bool(flags & torrent_flags::disable_lsd); - if (m_enable_lsd != new_value) set_need_save_resume(); + if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed); m_enable_lsd = new_value; } if (mask & torrent_flags::disable_pex) { bool const new_value = !bool(flags & torrent_flags::disable_pex); - if (m_enable_pex != new_value) set_need_save_resume(); + if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed); m_enable_pex = new_value; } } @@ -932,7 +962,7 @@ bool is_downloading_state(int const st) if (s == m_share_mode) return; m_share_mode = s; - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); #ifndef TORRENT_DISABLE_LOGGING debug_log("*** set-share-mode: %d", s); #endif @@ -957,7 +987,7 @@ bool is_downloading_state(int const st) debug_log("*** set-upload-mode: %d", b); #endif - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); update_gauge(); state_updated(); send_upload_only(); @@ -1108,6 +1138,22 @@ bool is_downloading_state(int const st) pause(); } + void torrent::handle_inconsistent_hashes(piece_index_t const piece) + { + auto const file_slices = torrent_file().map_block(piece, 0, 0); + file_index_t const file = file_slices.empty() ? torrent_status::error_file_none : file_slices[0].file_index; + set_error(errors::torrent_inconsistent_hashes, file); + // if this is a hybrid torrent, we may have marked some more pieces + // as "have" but not yet validated them against the v2 hashes. At + // this point, just assume we have no pieces + m_picker.reset(); + m_hash_picker.reset(); + m_file_progress.clear(); + m_have_all = false; + update_gauge(); + pause(); + } + void torrent::on_piece_fail_sync(piece_index_t const piece, piece_block) try { if (m_abort) return; @@ -1409,8 +1455,8 @@ bool is_downloading_state(int const st) peer_request torrent::to_req(piece_block const& p) const { - int block_offset = p.block_index * block_size(); - int block = std::min(torrent_file().piece_size( + int const block_offset = p.block_index * block_size(); + int const block = std::min(torrent_file().piece_size( p.piece_index) - block_offset, block_size()); TORRENT_ASSERT(block > 0); TORRENT_ASSERT(block <= block_size()); @@ -1434,6 +1480,18 @@ bool is_downloading_state(int const st) void torrent::add_extension(std::shared_ptr ext) { m_extensions.push_back(ext); + + for (auto p : m_connections) + { + TORRENT_INCREMENT(m_iterating_connections); + std::shared_ptr pp(ext->new_connection(peer_connection_handle(p->self()))); + if (pp) p->add_extension(std::move(pp)); + } + + // if files are checked for this torrent, call the extension + // to let it initialize itself + if (m_connections_initialized) + ext->on_files_checked(); } void torrent::remove_extension(std::shared_ptr ext) @@ -1450,18 +1508,6 @@ bool is_downloading_state(int const st) if (!tp) return; add_extension(tp); - - for (auto p : m_connections) - { - TORRENT_INCREMENT(m_iterating_connections); - std::shared_ptr pp(tp->new_connection(peer_connection_handle(p->self()))); - if (pp) p->add_extension(std::move(pp)); - } - - // if files are checked for this torrent, call the extension - // to let it initialize itself - if (m_connections_initialized) - tp->on_files_checked(); } #endif @@ -1819,7 +1865,7 @@ bool is_downloading_state(int const st) { // m_file_priority was loaded from the resume data, this doesn't // alter any state that needs to be saved in the resume data - bool const ns = m_need_save_resume_data; + auto const ns = m_need_save_resume_data; update_piece_priorities(m_file_priority); m_need_save_resume_data = ns; } @@ -2013,7 +2059,7 @@ bool is_downloading_state(int const st) // want anything in this function to affect the state of // m_need_save_resume_data, so we save it in a local variable and reset // it at the end of the function. - bool const need_save_resume_data = m_need_save_resume_data; + auto const need_save_resume_data = m_need_save_resume_data; TORRENT_ASSERT(is_single_thread()); @@ -2165,12 +2211,12 @@ bool is_downloading_state(int const st) m_picker->we_have(i); inc_stats_counter(counters::num_piece_passed); update_gauge(); - we_have(i); + we_have(i, true); } // --- UNFINISHED PIECES --- - int const num_blocks_per_piece = torrent_file().piece_length() / block_size(); + int const num_blocks_per_piece = torrent_file().blocks_per_piece(); for (auto const& p : m_add_torrent_params->unfinished_pieces) { @@ -2221,6 +2267,7 @@ bool is_downloading_state(int const st) if (should_start_full_check) { + stop_announcing(); set_state(torrent_status::checking_files); if (should_check_files()) start_checking(); @@ -2497,8 +2544,7 @@ bool is_downloading_state(int const st) if ((hash_passed[0] && !hash_passed[1]) || (!hash_passed[0] && hash_passed[1])) { - set_error(errors::torrent_inconsistent_hashes, torrent_status::error_file_none); - pause(); + handle_inconsistent_hashes(piece); return; } else if (hash_passed[0] || hash_passed[1]) @@ -2507,6 +2553,7 @@ bool is_downloading_state(int const st) { need_picker(); m_picker->we_have(piece); + set_need_save_resume(torrent_handle::if_download_progress); update_gauge(); } we_have(piece); @@ -2654,11 +2701,12 @@ bool is_downloading_state(int const st) // private torrents are never announced on LSD if (m_torrent_file->is_valid() && m_torrent_file->priv()) return; +#if TORRENT_USE_I2P // i2p torrents are also never announced on LSD // unless we allow mixed swarms - if (m_torrent_file->is_valid() - && (torrent_file().is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))) + if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) return; +#endif if (is_paused()) return; @@ -2697,6 +2745,10 @@ bool is_downloading_state(int const st) #ifndef TORRENT_DISABLE_LOGGING if (should_log()) { +#if TORRENT_USE_I2P + if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) + debug_log("DHT: i2p torrent (and mixed peers not allowed)"); +#endif if (!m_ses.announce_dht()) debug_log("DHT: no listen sockets"); @@ -2791,8 +2843,11 @@ bool is_downloading_state(int const st) get_handle(), int(peers.size())); } - if (torrent_file().priv() || (torrent_file().is_i2p() - && !settings().get_bool(settings_pack::allow_i2p_mixed))) return; +#if TORRENT_USE_I2P + if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) return; +#endif + + if (torrent_file().priv()) return; for (auto& p : peers) add_peer(p, peer_info::dht, v == protocol_version::V2 ? pex_lt_v2 : pex_flags_t(0)); @@ -2822,9 +2877,27 @@ bool is_downloading_state(int const st) namespace { void refresh_endpoint_list(aux::session_interface& ses + , std::string const& url , bool const is_ssl, bool const complete_sent , std::vector& aeps) { +#if TORRENT_USE_I2P + if (is_i2p_url(url)) + { + if (aeps.size() > 1) + { + aeps.erase(aeps.begin() + 1, aeps.end()); + } + else if (aeps.empty()) + { + aeps.emplace_back(aux::listen_socket_handle(), complete_sent); + } + return; + } +#else + TORRENT_UNUSED(url); +#endif + // update the endpoint list by adding entries for new listen sockets // and removing entries for non-existent ones std::size_t valid_endpoints = 0; @@ -3043,12 +3116,25 @@ namespace { #ifndef TORRENT_DISABLE_LOGGING ++idx; #endif - refresh_endpoint_list(m_ses, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints); + refresh_endpoint_list(m_ses, ae.url, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints); // if trackerid is not specified for tracker use default one, probably set explicitly req.trackerid = ae.trackerid.empty() ? m_trackerid : ae.trackerid; req.url = ae.url; +#if TORRENT_USE_I2P + if (is_i2p_url(req.url)) + { + req.kind |= tracker_request::i2p; + } + else if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) + { + // if we don't allow mixing normal peers into this i2p + // torrent, skip this announce + continue; + } +#endif + for (auto& aep : ae.endpoints) { // do not add code which continues to the next endpoint here! @@ -3139,13 +3225,6 @@ namespace { #endif req.key = tracker_key(); -#if TORRENT_USE_I2P - if (is_i2p()) - { - req.kind |= tracker_request::i2p; - } -#endif - req.outgoing_socket = aep.socket; req.info_hash = m_torrent_file->info_hashes().get(ih); @@ -3236,7 +3315,14 @@ namespace { req.kind |= tracker_request::scrape_request; auto& ae = m_trackers[idx]; - refresh_endpoint_list(m_ses, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints); + +#if TORRENT_USE_I2P + if (is_i2p_url(ae.url)) + req.kind |= tracker_request::i2p; + else if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) + return; +#endif + refresh_endpoint_list(m_ses, ae.url, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints); req.url = ae.url; req.private_torrent = m_torrent_file->priv(); #if TORRENT_ABI_VERSION == 1 @@ -3358,7 +3444,7 @@ namespace { update_auto_sequential(); // these numbers are cached in the resume data - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_counters_changed); } } @@ -3469,11 +3555,11 @@ namespace { continue; #if TORRENT_USE_I2P - if (r.i2pconn && string_ends_with(i.hostname, ".i2p")) + if (r.i2pconn) { // this is an i2p name, we need to use the SAM connection // to do the name lookup - if (string_ends_with(i.hostname, ".b32.i2p")) + if (string_ends_with(i.hostname, ".i2p")) { ADD_OUTSTANDING_ASYNC("torrent::on_i2p_resolve"); r.i2pconn->async_name_lookup(i.hostname.c_str() @@ -3484,7 +3570,7 @@ namespace { { torrent_state st = get_peer_list_state(); need_peer_list(); - if (m_peer_list->add_i2p_peer(i.hostname.c_str (), peer_info::tracker, {}, &st)) + if (m_peer_list->add_i2p_peer(i.hostname, peer_info::tracker, {}, &st)) state_updated(); peers_erased(st.erased); } @@ -3498,6 +3584,24 @@ namespace { } } +#if TORRENT_USE_I2P + if (r.i2pconn) + { + for (auto const& i : resp.i2p_peers) + { + torrent_state st = get_peer_list_state(); + peer_entry p; + std::string destination = base32encode_i2p(i.destination); + destination += ".b32.i2p"; + + ADD_OUTSTANDING_ASYNC("torrent::on_i2p_resolve"); + r.i2pconn->async_name_lookup(destination.c_str() + , [self = shared_from_this()] (error_code const& ec, char const* dest) + { self->torrent::on_i2p_resolve(ec, dest); }); + } + } +#endif + // there are 2 reasons to allow local IPs to be returned from a // non-local tracker // 1. retrackers are popular in russia, where an ISP runs a tracker within @@ -3549,8 +3653,12 @@ namespace { if (m_ses.alerts().should_post() || r.triggered_manually) { + int peer_count = int(resp.peers.size() + resp.peers4.size()); +#if TORRENT_USE_I2P + peer_count += int(resp.i2p_peers.size()); +#endif m_ses.alerts().emplace_alert( - get_handle(), local_endpoint, int(resp.peers.size() + resp.peers4.size()) + get_handle(), local_endpoint, peer_count + int(resp.peers6.size()), v, r.url); } @@ -3664,7 +3772,7 @@ namespace { for (auto& e : m_trackers) { // make sure we check for new endpoints from the listen sockets - refresh_endpoint_list(m_ses, is_ssl_torrent(), bool(m_complete_sent), e.endpoints); + refresh_endpoint_list(m_ses, e.url, is_ssl_torrent(), bool(m_complete_sent), e.endpoints); for (auto& aep : e.endpoints) { for (auto& a : aep.info_hashes) @@ -3736,6 +3844,8 @@ namespace { if (m_peer_list->add_i2p_peer(dest, peer_info::tracker, {}, &st)) state_updated(); peers_erased(st.erased); + + update_want_peers(); } catch (...) { handle_exception(); } #endif @@ -3963,8 +4073,7 @@ namespace { if (!error && ((passed && !v2_passed) || (!passed && v2_passed))) { - set_error(errors::torrent_inconsistent_hashes, torrent_status::error_file_none); - pause(); + handle_inconsistent_hashes(piece); return; } @@ -4049,7 +4158,7 @@ namespace { // piece, it just does all the torrent-level accounting that needs to // happen. It may not be called twice for the same piece (if it is, // file_progress will assert) - void torrent::we_have(piece_index_t const index) + void torrent::we_have(piece_index_t const index, bool const loading_resume) { TORRENT_ASSERT(is_single_thread()); TORRENT_ASSERT(!has_picker() || m_picker->has_piece_passed(index)); @@ -4116,9 +4225,12 @@ namespace { p->update_interest(); } - set_need_save_resume(); - state_updated(); - update_want_tick(); + if (!loading_resume) + { + set_need_save_resume(torrent_handle::if_download_progress); + state_updated(); + update_want_tick(); + } if (m_ses.alerts().should_post()) m_ses.alerts().emplace_alert(get_handle(), index); @@ -4171,7 +4283,7 @@ namespace { need_hash_picker(); int const blocks_in_piece = torrent_file().orig_files().blocks_in_piece2(piece); - int const blocks_per_piece = torrent_file().orig_files().piece_length() / default_block_size; + int const blocks_per_piece = torrent_file().blocks_per_piece(); // the blocks are guaranteed to represent exactly one piece TORRENT_ASSERT(blocks_in_piece == int(block_hashes.size())); @@ -4191,17 +4303,17 @@ namespace { , i * default_block_size, block_hashes[i]); last_result = result; + // all verified ranges should always be full pieces or less + TORRENT_ASSERT(result.first_verified_block >= 0 + || (result.first_verified_block % blocks_per_piece) == 0); + TORRENT_ASSERT(result.num_verified <= blocks_per_piece + || (result.num_verified % blocks_per_piece) == 0); + if (result.status == set_block_hash_result::result::success) { TORRENT_ASSERT(result.first_verified_block < blocks_in_piece); TORRENT_ASSERT(blocks_in_piece <= blocks_per_piece); - // all verified ranges should always be full pieces or less - TORRENT_ASSERT(result.first_verified_block >= 0 - || (result.first_verified_block % blocks_per_piece) == 0); - TORRENT_ASSERT(result.num_verified <= blocks_per_piece - || (result.num_verified % blocks_per_piece) == 0); - // note that result.num_verified may cover pad blocks too, and // so may be > blocks_in_piece @@ -4223,14 +4335,10 @@ namespace { TORRENT_ASSERT(first_block <= i); TORRENT_ASSERT(i < first_block + count); - using delta = piece_index_t::diff_type; - // if the hashes for more than one piece have been verified, // check for any pieces which were already checked but couldn't // be verified and mark them as verified - for (piece_index_t verified_piece = piece + delta(result.first_verified_block / blocks_per_piece) - , end = verified_piece + delta(result.num_verified / blocks_per_piece) - ; verified_piece < end; ++verified_piece) + for (piece_index_t verified_piece : result.piece_range(piece, blocks_per_piece)) { if (!has_picker() || verified_piece == piece @@ -4255,6 +4363,20 @@ namespace { // it actually failed. Otherwise it might have been failing // because of other, previously existing block hashes. ret = false; + + // if the hashes for more than one piece have been verified, + // check for any pieces which were already checked but couldn't + // be verified and mark them as verified + for (piece_index_t verified_piece : last_result.piece_range(piece, blocks_per_piece)) + { + if (!has_picker() + || verified_piece == piece) + continue; + + m_picker->we_dont_have(verified_piece); + update_gauge(); + piece_failed(verified_piece); + } } if (boost::indeterminate(ret) && std::all_of(block_passed.begin(), block_passed.end() @@ -4286,7 +4408,7 @@ namespace { TORRENT_ASSERT(index >= piece_index_t(0)); TORRENT_ASSERT(index < m_torrent_file->end_piece()); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_download_progress); inc_stats_counter(counters::num_piece_passed); @@ -4771,6 +4893,8 @@ namespace { { if (alerts().should_post()) alerts().emplace_alert(get_handle()); + alerts().emplace_alert(get_handle() + , info_hash(), get_userdata()); } // TODO: 2 abort lookups this torrent has made via the @@ -4817,7 +4941,7 @@ namespace { if (on == m_super_seeding) return; m_super_seeding = on; - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); state_updated(); if (m_super_seeding) return; @@ -4911,7 +5035,7 @@ namespace { , filename, m_torrent_file->files().file_path(file_idx), file_idx); m_torrent_file->rename_file(file_idx, filename); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); } } catch (...) { handle_exception(); } @@ -5188,6 +5312,13 @@ namespace { } #endif // TORRENT_DISABLE_STREAMING + void torrent::post_piece_availability() + { + aux::vector avail; + piece_availability(avail); + alerts().emplace_alert(get_handle(), std::move(avail)); + } + void torrent::piece_availability(aux::vector& avail) const { INVARIANT_CHECK; @@ -5293,7 +5424,7 @@ namespace { if (filter_updated) { // we need to save this new state - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); update_peer_interest(was_finished); } @@ -5336,7 +5467,7 @@ namespace { if (filter_updated) { // we need to save this new state - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); update_peer_interest(was_finished); #ifndef TORRENT_DISABLE_STREAMING @@ -5401,7 +5532,7 @@ namespace { { update_piece_priorities(prios); m_file_priority = std::move(prios); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); #ifndef TORRENT_DISABLE_SHARE_MODE if (m_share_mode) recalc_share_mode(); @@ -5474,7 +5605,7 @@ namespace { else { m_file_priority = std::move(new_priority); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); } } @@ -5523,7 +5654,7 @@ namespace { else { m_file_priority = std::move(new_priority); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); } } @@ -5655,6 +5786,12 @@ namespace { } } + void torrent::post_trackers() + { + auto t = trackers(); + m_ses.alerts().emplace_alert(get_handle(), std::move(t)); + } + std::vector torrent::trackers() const { std::vector ret; @@ -5734,7 +5871,7 @@ namespace { if (m_announcing && !m_trackers.empty()) announce_with_tracker(); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_metadata_changed); } void torrent::prioritize_udp_trackers() @@ -5784,7 +5921,7 @@ namespace { k->trackerid = url.trackerid; k->tier = url.tier; k->fail_limit = url.fail_limit; - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_metadata_changed); if (m_announcing && !m_trackers.empty()) announce_with_tracker(); return true; } @@ -6170,7 +6307,7 @@ namespace { , web->url, error_code(errors::blocked_by_idna)); } // never try it again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6206,7 +6343,7 @@ namespace { , libtorrent::errors::peer_banned); } // never try it again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6220,8 +6357,8 @@ namespace { { m_ses.alerts().emplace_alert(get_handle(), web->url, errors::unsupported_url_protocol); } - // never try it again - remove_web_seed_iter(web); + // never try it again for this session + web->disabled = true; return; } @@ -6257,7 +6394,7 @@ namespace { , web->url, errors::port_blocked); } // never try it again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6346,7 +6483,7 @@ namespace { // the name lookup failed for the http host. Don't try // this host again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6460,7 +6597,7 @@ namespace { // the name lookup failed for the http host. Don't try // this host again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6552,7 +6689,7 @@ namespace { , web->url, error_code(errors::blocked_by_idna)); } // never try it again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6576,7 +6713,7 @@ namespace { m_ses.alerts().emplace_alert(get_handle() , a, peer_blocked_alert::ssrf_mitigation); // never try it again - remove_web_seed_iter(web); + web->disabled = true; return; } @@ -6723,8 +6860,7 @@ namespace { { if (torrent_file().info_hashes().has_v1() && have_piece(p.first)) { - set_error(errors::torrent_inconsistent_hashes, torrent_status::error_file_none); - pause(); + handle_inconsistent_hashes(p.first); return result.valid; } @@ -6739,8 +6875,7 @@ namespace { { if (torrent_file().info_hashes().has_v1() && !have_piece(p)) { - set_error(errors::torrent_inconsistent_hashes, torrent_status::error_file_none); - pause(); + handle_inconsistent_hashes(p); return result.valid; } @@ -6841,8 +6976,8 @@ namespace { ret.finished_time = static_cast(total_seconds(finished_time())); ret.seeding_time = static_cast(total_seconds(seeding_time())); ret.last_seen_complete = m_last_seen_complete; - ret.last_upload = std::time_t(total_seconds(m_last_upload.time_since_epoch())); - ret.last_download = std::time_t(total_seconds(m_last_download.time_since_epoch())); + ret.last_upload = aux::to_time_t(m_last_upload); + ret.last_download = aux::to_time_t(m_last_download); ret.num_complete = m_complete; ret.num_incomplete = m_incomplete; @@ -6873,7 +7008,7 @@ namespace { // in either case; there will be no half-finished pieces. if (has_picker()) { - int const num_blocks_per_piece = torrent_file().piece_length() / block_size(); + int const num_blocks_per_piece = torrent_file().blocks_per_piece(); std::vector const q = m_picker->get_download_queue(); @@ -7134,22 +7269,22 @@ namespace { } } - void torrent::get_download_queue(std::vector* queue) const + void torrent::post_peer_info() { - TORRENT_ASSERT(is_single_thread()); - queue->clear(); - std::vector& blk = m_ses.block_info_storage(); - blk.clear(); - - if (!valid_metadata() || !has_picker()) return; - piece_picker const& p = picker(); - std::vector q - = p.get_download_queue(); - if (q.empty()) return; - - const int blocks_per_piece = m_picker->blocks_in_piece(piece_index_t(0)); - blk.resize(q.size() * aux::numeric_cast(blocks_per_piece)); + std::vector v; + get_peer_info(&v); + alerts().emplace_alert(get_handle(), std::move(v)); + } +namespace { + void initialize_piece_info(piece_picker const& p + , torrent_info const& ti + , int const block_size + , std::vector& blk + , span q + , std::vector* queue) + { + const int blocks_per_piece = p.blocks_in_piece(piece_index_t(0)); int counter = 0; for (auto i = q.begin(); i != q.end(); ++i, ++counter) { @@ -7164,16 +7299,16 @@ namespace { TORRENT_ASSERT(counter * blocks_per_piece + pi.blocks_in_piece <= int(blk.size())); block_info* blocks = &blk[std::size_t(counter * blocks_per_piece)]; pi.blocks = blocks; - int const piece_size = torrent_file().piece_size(i->index); + int const piece_size = ti.piece_size(i->index); int idx = -1; - for (auto const& info : m_picker->blocks_for_piece(*i)) + for (auto const& info : p.blocks_for_piece(*i)) { ++idx; block_info& bi = blocks[idx]; bi.state = info.state; bi.block_size = idx < pi.blocks_in_piece - 1 - ? aux::numeric_cast(block_size()) - : aux::numeric_cast(piece_size - (idx * block_size())); + ? aux::numeric_cast(block_size) + : aux::numeric_cast(piece_size - (idx * block_size)); bool const complete = bi.state == block_info::writing || bi.state == block_info::finished; if (info.peer == nullptr) @@ -7220,7 +7355,42 @@ namespace { pi.piece_index = i->index; queue->push_back(pi); } + } +} + + void torrent::post_download_queue() + { + std::vector blk; + if (!valid_metadata() || !has_picker()) return; + piece_picker const& p = picker(); + std::vector const q = p.get_download_queue(); + std::vector queue; + if (!q.empty()) + { + const int blocks_per_piece = m_picker->blocks_in_piece(piece_index_t(0)); + blk.resize(q.size() * aux::numeric_cast(blocks_per_piece)); + initialize_piece_info(p, torrent_file(), block_size(), blk, q, &queue); + } + alerts().emplace_alert(get_handle(), std::move(queue), std::move(blk)); + } + + void torrent::get_download_queue(std::vector* queue) const + { + TORRENT_ASSERT(is_single_thread()); + queue->clear(); + std::vector& blk = m_ses.block_info_storage(); + blk.clear(); + + if (!valid_metadata() || !has_picker()) return; + piece_picker const& p = picker(); + std::vector q + = p.get_download_queue(); + if (q.empty()) return; + + const int blocks_per_piece = m_picker->blocks_in_piece(piece_index_t(0)); + blk.resize(q.size() * aux::numeric_cast(blocks_per_piece)); + initialize_piece_info(p, torrent_file(), block_size(), blk, q, queue); } #if defined TORRENT_SSL_PEERS @@ -7293,7 +7463,7 @@ namespace { #if TORRENT_USE_I2P if (peerinfo->is_i2p_addr) { - if (m_ses.i2p_proxy().hostname.empty()) + if (settings().get_str(settings_pack::i2p_hostname).empty()) { // we have an i2p torrent, but we're not connected to an i2p // SAM proxy. @@ -7339,11 +7509,19 @@ namespace { // one. The main feature of a peer connection is that whether or not we // proxy it is configurable. When we use i2p, we want to always prox // everything via i2p. + + aux::proxy_settings proxy; + proxy.hostname = settings().get_str(settings_pack::i2p_hostname); + proxy.port = std::uint16_t(settings().get_int(settings_pack::i2p_port)); + proxy.type = settings_pack::i2p_proxy; + aux::socket_type ret = instantiate_connection(m_ses.get_context() - , m_ses.i2p_proxy(), nullptr, nullptr, false, false); - boost::get(ret).set_destination(static_cast(peerinfo)->dest()); - boost::get(ret).set_command(i2p_stream::cmd_connect); - boost::get(ret).set_session_id(m_ses.i2p_session()); + , proxy, nullptr, nullptr, false, false); + i2p_stream& str = boost::get(ret); + str.set_local_i2p_endpoint(m_ses.local_i2p_endpoint()); + str.set_destination(static_cast(peerinfo)->dest()); + str.set_command(i2p_stream::cmd_connect); + str.set_session_id(m_ses.i2p_session()); return ret; } else @@ -7420,7 +7598,7 @@ namespace { m_peers_to_disconnect.reserve(m_connections.size() + 1); sorted_insert(m_connections, c.get()); - TORRENT_TRY + try { m_outgoing_pids.insert(our_pid); m_ses.insert_peer(c); @@ -7437,7 +7615,7 @@ namespace { if (c->is_disconnecting()) return false; } - TORRENT_CATCH (std::exception const&) + catch (std::exception const&) { TORRENT_ASSERT(m_iterating_connections == 0); c->disconnect(errors::no_error, operation_t::bittorrent, peer_connection_interface::failure); @@ -7468,7 +7646,7 @@ namespace { continue; } m_merkle_trees.emplace_back(fs.file_num_blocks(i) - , fs.piece_length() / default_block_size, fs.root_ptr(i)); + , fs.blocks_per_piece(), fs.root_ptr(i)); auto const piece_layer = m_torrent_file->piece_layer(i); if (piece_layer.empty()) { @@ -7630,7 +7808,7 @@ namespace { for (auto p : m_connections) p->disconnect_if_redundant(); - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_metadata_changed); return true; } @@ -8360,7 +8538,7 @@ namespace { if (m_super_seeding) { m_super_seeding = false; - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); state_updated(); } #endif @@ -8559,7 +8737,7 @@ namespace { m_save_path = save_path; #endif - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); } } @@ -8575,7 +8753,7 @@ namespace { if (alerts().should_post()) alerts().emplace_alert(get_handle(), path, m_save_path); m_save_path = path; - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); if (status == status_t::need_full_check) force_recheck(); } @@ -8866,7 +9044,7 @@ namespace { debug_log("*** set-sequential-download: %d", sd); #endif - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); state_updated(); } @@ -8912,7 +9090,8 @@ namespace { TORRENT_ASSERT(is_single_thread()); // TODO: perhaps 0 should actially mean 0 if (limit <= 0) limit = (1 << 24) - 1; - if (int(m_max_uploads) != limit && state_update) state_updated(); + if (int(m_max_uploads) == limit) return; + if (state_update) state_updated(); m_max_uploads = aux::numeric_cast(limit); #ifndef TORRENT_DISABLE_LOGGING if (should_log() && state_update) @@ -8920,7 +9099,7 @@ namespace { #endif if (state_update) - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); } void torrent::set_max_connections(int limit, bool const state_update) @@ -8928,7 +9107,8 @@ namespace { TORRENT_ASSERT(is_single_thread()); // TODO: perhaps 0 should actially mean 0 if (limit <= 0) limit = (1 << 24) - 1; - if (int(m_max_connections) != limit && state_update) state_updated(); + if (int(m_max_connections) == limit) return; + if (state_update) state_updated(); m_max_connections = aux::numeric_cast(limit); update_want_peers(); @@ -8944,13 +9124,12 @@ namespace { } if (state_update) - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); } void torrent::set_upload_limit(int const limit) { set_limit_impl(limit, peer_connection::upload_channel); - set_need_save_resume(); #ifndef TORRENT_DISABLE_LOGGING debug_log("*** set-upload-limit: %d", limit); #endif @@ -8959,7 +9138,6 @@ namespace { void torrent::set_download_limit(int const limit) { set_limit_impl(limit, peer_connection::download_channel); - set_need_save_resume(); #ifndef TORRENT_DISABLE_LOGGING debug_log("*** set-download-limit: %d", limit); #endif @@ -8978,8 +9156,12 @@ namespace { struct peer_class* tpc = m_ses.peer_classes().at(m_peer_class); TORRENT_ASSERT(tpc); - if (tpc->channel[channel].throttle() != limit && state_update) + if (tpc->channel[channel].throttle() == limit) return; + if (state_update) + { state_updated(); + set_need_save_resume(torrent_handle::if_config_changed); + } tpc->channel[channel].throttle(limit); } @@ -9113,7 +9295,7 @@ namespace { state_updated(); // we need to save this new state as well - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_config_changed); // recalculate which torrents should be // paused @@ -9223,9 +9405,6 @@ namespace { } // this is an async operation triggered by the client - // TODO: add a flag to ignore stats, and only care about resume data for - // content. For unchanged files, don't trigger a load of the metadata - // just to save an empty resume data file void torrent::save_resume_data(resume_data_flags_t const flags) { TORRENT_ASSERT(is_single_thread()); @@ -9238,14 +9417,26 @@ namespace { return; } - if ((flags & torrent_handle::only_if_modified) && !m_need_save_resume_data) + auto conditions = flags & ( + torrent_handle::only_if_modified + | torrent_handle::if_counters_changed + | torrent_handle::if_download_progress + | torrent_handle::if_config_changed + | torrent_handle::if_state_changed + | torrent_handle::if_metadata_changed + ); + + if (conditions && !(m_need_save_resume_data & conditions)) { + // if conditions were specified, but none of those conditions are + // met (i.e. none of them have been updated since last + // save_resume_data()), we don't save it. alerts().emplace_alert(get_handle() , errors::resume_data_not_modified); return; } - m_need_save_resume_data = false; + m_need_save_resume_data = resume_data_flags_t{}; state_updated(); if ((flags & torrent_handle::flush_disk_cache) && m_storage) @@ -9304,6 +9495,9 @@ namespace { // there should be no more disk activity for this torrent now, we can // release the disk io handle m_storage.reset(); + + alerts().emplace_alert(get_handle() + , info_hash(), get_userdata()); } bool torrent::is_paused() const @@ -9319,7 +9513,7 @@ namespace { if (!m_paused) { // we need to save this new state - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); } set_paused(true, flags); @@ -9489,9 +9683,23 @@ namespace { // don't add duplicates auto const it = std::find(m_web_seeds.begin(), m_web_seeds.end(), ent); - if (it != m_web_seeds.end()) return &*it; + if (it != m_web_seeds.end()) + { + // if we're adding a web seed (as non-ephemeral) and we have an + // ephemeral web seed already, promote it to non-ephemeral + if (it->ephemeral && !ent.ephemeral) + { + set_need_save_resume(torrent_handle::if_metadata_changed); + it->ephemeral = false; + } + return &*it; + } m_web_seeds.emplace_back(std::move(ent)); - set_need_save_resume(); + + // ephemeral web seeds are not saved in the resume data + if (!ent.ephemeral) + set_need_save_resume(torrent_handle::if_metadata_changed); + update_want_tick(); return &m_web_seeds.back(); } @@ -9566,7 +9774,7 @@ namespace { update_gauge(); // we need to save this new state - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_state_changed); do_resume(); } @@ -9718,13 +9926,18 @@ namespace { #endif if (settings().get_bool(settings_pack::announce_to_all_tiers) + && !settings().get_bool(settings_pack::announce_to_all_trackers) && state.found_working && t.tier <= state.tier && state.tier != INT_MAX) continue; - if (t.tier > state.tier && !settings().get_bool(settings_pack::announce_to_all_tiers)) break; - if (a.is_working()) { state.tier = t.tier; state.found_working = false; } + if (t.tier > state.tier) + { + if (!settings().get_bool(settings_pack::announce_to_all_tiers)) break; + state.found_working = false; + } + state.tier = t.tier; if (a.fails >= t.fail_limit && t.fail_limit != 0) continue; if (a.updating) { @@ -9733,8 +9946,7 @@ namespace { else { time_point32 const next_tracker_announce = std::max(a.next_announce, a.min_announce); - if (next_tracker_announce < next_announce - && (!state.found_working || a.is_working())) + if (next_tracker_announce < next_announce) next_announce = next_tracker_announce; } if (a.is_working()) state.found_working = true; @@ -10039,7 +10251,7 @@ namespace { // these counters are saved in the resume data, since they updated // we need to save the resume data too - set_need_save_resume(); + set_need_save_resume(torrent_handle::if_counters_changed); // if the rate is 0, there's no update because of network transfers if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0) @@ -10132,7 +10344,7 @@ namespace { for (auto i = m_web_seeds.begin(); i != m_web_seeds.end() && limit > 0;) { auto const w = i++; - if (w->removed || w->retry > now || !w->interesting) + if (w->disabled || w->removed || w->retry > now || !w->interesting) continue; --limit; @@ -10864,46 +11076,19 @@ namespace { if (i != m_web_seeds.end()) { + if (!i->ephemeral) + set_need_save_resume(torrent_handle::if_metadata_changed); remove_web_seed_iter(i); - set_need_save_resume(); } } - void torrent::disconnect_web_seed(peer_connection* p) - { - auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end() - , [p] (web_seed_t const& ws) { return ws.peer_info.connection == p; }); - - // this happens if the web server responded with a redirect - // or with something incorrect, so that we removed the web seed - // immediately, before we disconnected - if (i == m_web_seeds.end()) return; - - TORRENT_ASSERT(i->resolving == false); - - TORRENT_ASSERT(i->peer_info.connection); - i->peer_info.connection = nullptr; - } - - void torrent::remove_web_seed_conn(peer_connection* p, error_code const& ec - , operation_t const op, disconnect_severity_t const error) + void torrent::remove_web_seed_conn(peer_connection* p) { auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end() , [p] (web_seed_t const& ws) { return ws.peer_info.connection == p; }); TORRENT_ASSERT(i != m_web_seeds.end()); if (i == m_web_seeds.end()) return; - - auto* peer = static_cast(i->peer_info.connection); - if (peer != nullptr) - { - // if we have a connection for this web seed, we also need to - // disconnect it and clear its reference to the peer_info object - // that's part of the web_seed_t we're about to remove - TORRENT_ASSERT(peer->m_in_use == 1337); - peer->disconnect(ec, op, error); - peer->set_peer_info(nullptr); - } remove_web_seed_iter(i); } @@ -10915,7 +11100,7 @@ namespace { TORRENT_ASSERT(i != m_web_seeds.end()); if (i == m_web_seeds.end()) return; - if (i->removed) return; + if (i->removed || i->disabled) return; i->retry = aux::time_now32() + value_or(retry, seconds32( settings().get_int(settings_pack::urlseed_wait_retry))); } @@ -11186,21 +11371,41 @@ namespace { peers_erased(st.erased); } + // this call will disconnect any peers whose remote port is < 1024 + void torrent::privileged_port_updated() + { + if (!m_peer_list) return; + + port_filter ports; + ports.add_rule(0, 1023, port_filter::blocked); + + torrent_state st = get_peer_list_state(); + std::vector banned; + m_peer_list->apply_port_filter(ports, &st, banned); + + if (alerts().should_post()) + { + for (auto const& ep : banned) + alerts().emplace_alert(get_handle() + , ep, peer_blocked_alert::privileged_ports); + } + + peers_erased(st.erased); + } + void torrent::port_filter_updated() { - if (!m_apply_ip_filter) return; if (!m_peer_list) return; torrent_state st = get_peer_list_state(); - std::vector
        banned; + std::vector banned; m_peer_list->apply_port_filter(m_ses.get_port_filter(), &st, banned); if (alerts().should_post()) { - for (auto const& addr : banned) + for (auto const& ep : banned) alerts().emplace_alert(get_handle() - , tcp::endpoint(addr, 0) - , peer_blocked_alert::port_filter); + , ep, peer_blocked_alert::port_filter); } peers_erased(st.erased); @@ -11249,7 +11454,15 @@ namespace { #endif #endif // TORRENT_ABI_VERSION - void torrent::file_progress(aux::vector& fp, file_progress_flags_t const flags) + void torrent::post_file_progress(file_progress_flags_t const flags) + { + aux::vector fp; + file_progress(fp, flags); + alerts().emplace_alert(get_handle(), std::move(fp)); + } + + void torrent::file_progress(aux::vector& fp + , file_progress_flags_t const flags) { TORRENT_ASSERT(is_single_thread()); if (!valid_metadata()) @@ -11518,6 +11731,14 @@ namespace { m_links[aux::session_interface::torrent_state_updates].insert(list, this); } + void torrent::post_status(status_flags_t const flags) + { + std::vector s; + s.resize(1); + status(&s.front(), flags); + m_ses.alerts().emplace_alert(std::move(s)); + } + void torrent::status(torrent_status* st, status_flags_t const flags) { INVARIANT_CHECK; @@ -11564,7 +11785,7 @@ namespace { st->completed_time = m_completed_time; #if TORRENT_ABI_VERSION == 1 - st->last_scrape = static_cast(total_seconds(aux::time_now32() - m_last_scrape)); + st->last_scrape = static_cast(total_seconds(now - m_last_scrape)); #endif #if TORRENT_ABI_VERSION == 1 @@ -11601,9 +11822,9 @@ namespace { time_point32 const unset{seconds32(0)}; st->time_since_upload = m_last_upload == unset ? -1 - : static_cast(total_seconds(aux::time_now32() - m_last_upload)); + : static_cast(total_seconds(now - m_last_upload)); st->time_since_download = m_last_download == unset ? -1 - : static_cast(total_seconds(aux::time_now32() - m_last_download)); + : static_cast(total_seconds(now - m_last_download)); #endif st->finished_duration = finished_time(); @@ -11717,7 +11938,7 @@ namespace { // if we don't have any metadata, stop here st->queue_position = queue_position(); - st->need_save_resume = need_save_resume_data(); + st->need_save_resume = bool(m_need_save_resume_data); #if TORRENT_ABI_VERSION == 1 st->ip_filter_applies = m_apply_ip_filter; #endif diff --git a/3rd/libtorrent-rasterbar/src/torrent_handle.cpp b/3rd/libtorrent-rasterbar/src/torrent_handle.cpp index f21d18de..6f741512 100644 --- a/3rd/libtorrent-rasterbar/src/torrent_handle.cpp +++ b/3rd/libtorrent-rasterbar/src/torrent_handle.cpp @@ -69,6 +69,12 @@ namespace libtorrent { constexpr resume_data_flags_t torrent_handle::flush_disk_cache; constexpr resume_data_flags_t torrent_handle::save_info_dict; constexpr resume_data_flags_t torrent_handle::only_if_modified; + constexpr resume_data_flags_t torrent_handle::if_counters_changed; + constexpr resume_data_flags_t torrent_handle::if_download_progress; + constexpr resume_data_flags_t torrent_handle::if_config_changed; + constexpr resume_data_flags_t torrent_handle::if_state_changed; + constexpr resume_data_flags_t torrent_handle::if_metadata_changed; + constexpr add_piece_flags_t torrent_handle::overwrite_existing; constexpr pause_flags_t torrent_handle::graceful_pause; constexpr pause_flags_t torrent_handle::clear_disk_cache; @@ -124,13 +130,13 @@ namespace libtorrent { (t.get()->*f)(std::move(a)...); #ifndef BOOST_NO_EXCEPTIONS } catch (system_error const& e) { - ses.alerts().emplace_alert(torrent_handle(m_torrent) + ses.alerts().emplace_alert(torrent_handle(t) , e.code(), e.what()); } catch (std::exception const& e) { - ses.alerts().emplace_alert(torrent_handle(m_torrent) + ses.alerts().emplace_alert(torrent_handle(t) , error_code(), e.what()); } catch (...) { - ses.alerts().emplace_alert(torrent_handle(m_torrent) + ses.alerts().emplace_alert(torrent_handle(t) , error_code(), "unknown error"); } #endif @@ -392,7 +398,19 @@ namespace libtorrent { bool torrent_handle::need_save_resume_data() const { - return sync_call_ret(false, &torrent::need_save_resume_data); + auto const all_categories + = torrent_handle::if_counters_changed + | torrent_handle::if_download_progress + | torrent_handle::if_config_changed + | torrent_handle::if_state_changed + | torrent_handle::if_metadata_changed + ; + return sync_call_ret(false, &torrent::need_save_resume_data, all_categories); + } + + bool torrent_handle::need_save_resume_data(resume_data_flags_t const flags) const + { + return sync_call_ret(false, &torrent::need_save_resume_data, flags); } void torrent_handle::force_recheck() const @@ -469,6 +487,11 @@ namespace libtorrent { return std::move(ret); } + void torrent_handle::post_file_progress(file_progress_flags_t const flags) const + { + async_call(&torrent::post_file_progress, flags); + } + torrent_status torrent_handle::status(status_flags_t const flags) const { torrent_status st; @@ -476,6 +499,16 @@ namespace libtorrent { return st; } + void torrent_handle::post_status(status_flags_t const flags) const + { + async_call(&torrent::post_status, flags); + } + + void torrent_handle::post_piece_availability() const + { + async_call(&torrent::post_piece_availability); + } + void torrent_handle::piece_availability(std::vector& avail) const { auto availr = std::ref(static_cast&>(avail)); @@ -648,6 +681,11 @@ namespace libtorrent { return sync_call_ret>(empty, &torrent::trackers); } + void torrent_handle::post_trackers() const + { + async_call(&torrent::post_trackers); + } + void torrent_handle::add_url_seed(std::string const& url) const { async_call(&torrent::add_web_seed, url, web_seed_entry::url_seed @@ -857,6 +895,11 @@ namespace libtorrent { sync_call(&torrent::get_peer_info, vp); } + void torrent_handle::post_peer_info() const + { + async_call(&torrent::post_peer_info); + } + void torrent_handle::get_download_queue(std::vector& queue) const { auto queuep = &queue; @@ -870,6 +913,11 @@ namespace libtorrent { return queue; } + void torrent_handle::post_download_queue() const + { + async_call(&torrent::post_download_queue); + } + void torrent_handle::set_piece_deadline(piece_index_t index, int deadline , deadline_flags_t const flags) const { diff --git a/3rd/libtorrent-rasterbar/src/torrent_info.cpp b/3rd/libtorrent-rasterbar/src/torrent_info.cpp index 28581af1..d64387a5 100644 --- a/3rd/libtorrent-rasterbar/src/torrent_info.cpp +++ b/3rd/libtorrent-rasterbar/src/torrent_info.cpp @@ -208,10 +208,12 @@ namespace aux { element = string_view(); } #endif +#ifdef TORRENT_WINDOWS // this counts the number of unicode characters // we've added (which is different from the number // of bytes) int unicode_chars = 0; +#endif int added = 0; // the number of dots we've added @@ -234,7 +236,9 @@ namespace aux { // invalid utf8 sequence, replace with "_" path += '_'; ++added; +#ifdef TORRENT_WINDOWS ++unicode_chars; +#endif continue; } @@ -248,7 +252,9 @@ namespace aux { if (code_point == '.') ++num_dots; added += seq_len; +#ifdef TORRENT_WINDOWS ++unicode_chars; +#endif // any given path element should not // be more than 255 characters @@ -1427,6 +1433,15 @@ namespace { return false; } + std::set all_file_roots; + auto const& fs = orig_files(); + for (file_index_t i : fs.file_range()) + { + if (fs.file_size(i) <= fs.piece_length()) + continue; + all_file_roots.insert(fs.root(i)); + } + for (int i = 0; i < e.dict_size(); ++i) { auto const f = e.dict_at(i); @@ -1438,20 +1453,28 @@ namespace { return false; } + sha256_hash const root(f.first); + if (all_file_roots.find(root) == all_file_roots.end()) + { + // This piece layer doesn't refer to any file in this torrent + ec = errors::torrent_invalid_piece_layer; + return false; + } + piece_layers.emplace(sha256_hash(f.first), f.second.string_value()); } - m_piece_layers.resize(orig_files().num_files()); + m_piece_layers.resize(fs.num_files()); - for (file_index_t i : orig_files().file_range()) + for (file_index_t i : fs.file_range()) { - if (orig_files().file_size(i) <= orig_files().piece_length()) + if (fs.file_size(i) <= fs.piece_length()) continue; - auto const piece_layer = piece_layers.find(orig_files().root(i)); + auto const piece_layer = piece_layers.find(fs.root(i)); if (piece_layer == piece_layers.end()) continue; - int const num_pieces = orig_files().file_num_pieces(i); + int const num_pieces = fs.file_num_pieces(i); if (ptrdiff_t(piece_layer->second.size()) != num_pieces * sha256_hash::size()) { diff --git a/3rd/libtorrent-rasterbar/src/upnp.cpp b/3rd/libtorrent-rasterbar/src/upnp.cpp index 062a8aaa..3609cbd8 100644 --- a/3rd/libtorrent-rasterbar/src/upnp.cpp +++ b/3rd/libtorrent-rasterbar/src/upnp.cpp @@ -433,7 +433,7 @@ void upnp::resend_request(error_code const& ec) void upnp::connect(rootdevice& d) { TORRENT_ASSERT(d.magic == 1337); - TORRENT_TRY + try { #ifndef TORRENT_DISABLE_LOGGING log("connecting to: %s", d.url.c_str()); @@ -452,9 +452,8 @@ void upnp::connect(rootdevice& d) ); d.upnp_connection->get(d.url, seconds(30)); } - TORRENT_CATCH (std::exception const& exc) + catch (std::exception const& exc) { - TORRENT_DECLARE_DUMMY(std::exception, exc); TORRENT_UNUSED(exc); #ifndef TORRENT_DISABLE_LOGGING log("connection failed to: %s %s", d.url.c_str(), exc.what()); diff --git a/3rd/libtorrent-rasterbar/src/utp_socket_manager.cpp b/3rd/libtorrent-rasterbar/src/utp_socket_manager.cpp index 279eef24..2cc71d48 100644 --- a/3rd/libtorrent-rasterbar/src/utp_socket_manager.cpp +++ b/3rd/libtorrent-rasterbar/src/utp_socket_manager.cpp @@ -161,9 +161,14 @@ namespace aux { return m_last_socket->incoming_packet(p, ep, receive_time); } + // we send the deferred ACK when the socket is drained as well, + // so as long as the incoming packets go to the last socket + // (m_last_socket) we can derfer the ACK more. However, if we + // receive a packet for another socket, we have to trigger the + // ACK in case the new socket also wants to defer an ACK. if (m_deferred_ack) { - m_deferred_ack->send_ack(); + m_deferred_ack->send_deferred_ack(); m_deferred_ack = nullptr; } @@ -253,7 +258,7 @@ namespace aux { { utp_socket_impl* s = m_deferred_ack; m_deferred_ack = nullptr; - s->send_ack(); + s->send_deferred_ack(); } if (!m_drained_event.empty()) @@ -271,6 +276,13 @@ namespace aux { m_deferred_ack = s; } + void utp_socket_manager::cancel_deferred_ack(utp_socket_impl* s) + { + if (m_deferred_ack == s) + m_deferred_ack = nullptr; + } + + void utp_socket_manager::subscribe_drained(utp_socket_impl* s) { TORRENT_ASSERT(std::find(m_drained_event.begin(), m_drained_event.end(), s) diff --git a/3rd/libtorrent-rasterbar/src/utp_stream.cpp b/3rd/libtorrent-rasterbar/src/utp_stream.cpp index 176b6c78..f55e4e22 100644 --- a/3rd/libtorrent-rasterbar/src/utp_stream.cpp +++ b/3rd/libtorrent-rasterbar/src/utp_stream.cpp @@ -168,7 +168,8 @@ utp_socket_impl::utp_socket_impl(std::uint16_t const recv_id , m_recv_id(recv_id) , m_delay_sample_idx(0) , m_state(static_cast(state_t::none)) - , m_eof(false) + , m_in_eof(false) + , m_out_eof(false) , m_attached(true) , m_nagle(true) , m_slow_start(true) @@ -224,10 +225,10 @@ udp::endpoint utp_socket_impl::remote_endpoint() const return {m_remote_address, m_port}; } -void utp_socket_impl::send_ack() +void utp_socket_impl::send_deferred_ack() { - if (!m_deferred_ack) - return; + TORRENT_ASSERT(m_deferred_ack); + if (!m_deferred_ack) return; m_deferred_ack = false; send_pkt(utp_socket_impl::pkt_ack); } @@ -240,8 +241,8 @@ void utp_socket_impl::socket_drained() // more packets this round. So, we may want to // call the receive callback function to // let the user consume it - maybe_trigger_receive_callback(); - maybe_trigger_send_callback(); + maybe_trigger_receive_callback({}); + maybe_trigger_send_callback({}); } void utp_socket_impl::update_mtu_limits() @@ -312,12 +313,7 @@ close_reason_t utp_stream::get_close_reason() const void utp_stream::close() { if (!m_impl) return; - if (!m_impl->destroy()) - { - if (!m_impl) return; - m_impl->detach(); - m_impl = nullptr; - } + m_impl->close(); } std::size_t utp_stream::available() const @@ -435,6 +431,17 @@ void utp_stream::on_write(utp_stream* s, std::size_t const bytes_transferred } } +void utp_stream::on_writeable(utp_stream* s, error_code const& ec) +{ + UTP_LOGV("%8p: calling writeable handler ec:%s\n" + , static_cast(s->m_impl) + , ec.message().c_str()); + + TORRENT_ASSERT(s->m_writeable_handler); + post(s->m_io_service, std::bind(std::move(s->m_writeable_handler), ec)); + s->m_writeable_handler = nullptr; +} + void utp_stream::on_connect(utp_stream* s, error_code const& ec, bool const shutdown) { TORRENT_ASSERT(s); @@ -490,9 +497,9 @@ void utp_stream::issue_read() m_impl->issue_read(); } -std::size_t utp_stream::read_some(bool const clear_buffers) +std::size_t utp_stream::read_some(bool const clear_buffers, error_code& ec) { - return m_impl->read_some(clear_buffers); + return m_impl->read_some(clear_buffers, ec); } // Warning: this is always non-blocking, it only tries to send @@ -509,6 +516,11 @@ void utp_stream::issue_write() m_impl->issue_write(); } +void utp_stream::subscribe_writeable() +{ + m_impl->subscribe_writeable(); +} + void utp_stream::do_connect(tcp::endpoint const& ep) { m_impl->do_connect(ep); @@ -526,6 +538,7 @@ void utp_socket_impl::add_read_buffer(void* buf, int const len) void utp_socket_impl::add_write_buffer(void const* buf, int const len) { + TORRENT_ASSERT(!m_out_eof); UTP_LOGV("%8p: add_write_buffer %d bytes\n", static_cast(this), len); if (len <= 0) return; @@ -570,12 +583,14 @@ void utp_socket_impl::issue_read() // have some data in the read buffer, move it into the // client's buffer right away - m_read += int(read_some(false)); - maybe_trigger_receive_callback(); + error_code read_error; + m_read += int(read_some(false, read_error)); + maybe_trigger_receive_callback(read_error); } -std::size_t utp_socket_impl::read_some(bool const clear_buffers) +std::size_t utp_socket_impl::read_some(bool const clear_buffers, error_code& ec) { + ec.clear(); TORRENT_ASSERT(m_receive_buffer_size >= 0); if (m_receive_buffer_size <= 0) { @@ -584,6 +599,13 @@ std::size_t utp_socket_impl::read_some(bool const clear_buffers) m_read_buffer_size = 0; m_read_buffer.clear(); } + // if we have passed all data up to the application, and we're at EOF, set ec to eof + if (m_receive_buffer.empty() + && m_in_eof + && m_in_eof_seq_nr == m_ack_nr) + { + ec = boost::asio::error::eof; + } return 0; } @@ -666,6 +688,15 @@ std::size_t utp_socket_impl::read_some(bool const clear_buffers) m_read_buffer.clear(); } TORRENT_ASSERT(ret > 0 || m_null_buffers); + + // if we have passed all data up to the application, and we're at EOF, set ec to eof + if (ret == 0 + && m_receive_buffer.empty() + && m_in_eof + && m_in_eof_seq_nr == m_ack_nr) + { + ec = boost::asio::error::eof; + } return ret; } @@ -677,9 +708,17 @@ void utp_socket_impl::issue_write() TORRENT_ASSERT(m_write_buffer_size > 0); TORRENT_ASSERT(m_write_handler == false); TORRENT_ASSERT(m_userdata); + TORRENT_ASSERT(!m_out_eof); m_write_handler = true; m_written = 0; + if (m_out_eof) + { + // this happens if the application keeps trying to send data after + // having closed the socket + maybe_trigger_send_callback(boost::asio::error::eof); + return; + } if (test_socket_state()) return; // try to write. send_pkt returns false if there's @@ -687,7 +726,14 @@ void utp_socket_impl::issue_write() // is full and we can't send more packets right now while (send_pkt()); - maybe_trigger_send_callback(); + maybe_trigger_send_callback({}); +} + +void utp_socket_impl::subscribe_writeable() +{ + TORRENT_ASSERT(!m_writeable_handler); + m_writeable_handler = true; + maybe_trigger_writeable_callback({}); } bool utp_socket_impl::check_fin_sent() const @@ -729,8 +775,13 @@ utp_socket_impl::~utp_socket_impl() { INVARIANT_CHECK; + if (m_deferred_ack) + { + m_deferred_ack = false; + m_sm.cancel_deferred_ack(this); + } + TORRENT_ASSERT(!m_attached); - TORRENT_ASSERT(!m_deferred_ack); m_sm.inc_stats_counter(counters::num_utp_idle + m_state, -1); @@ -790,38 +841,59 @@ bool utp_socket_impl::should_delete() const return ret; } -void utp_socket_impl::maybe_trigger_receive_callback() +void utp_socket_impl::maybe_trigger_receive_callback(error_code const& ec) { INVARIANT_CHECK; if (m_read_handler == false) return; // nothing has been read or there's no outstanding read operation - if (m_null_buffers && m_receive_buffer_size == 0) return; - else if (!m_null_buffers && m_read == 0) return; + if (m_null_buffers && m_receive_buffer_size == 0 && !ec) return; + else if (!m_null_buffers && m_read == 0 && !ec) return; UTP_LOGV("%8p: calling read handler read:%d\n", static_cast(this), m_read); m_read_handler = false; - utp_stream::on_read(m_userdata, aux::numeric_cast(m_read), m_error, false); + error_code const error_to_report = ec ? ec : m_error; + utp_stream::on_read(m_userdata, aux::numeric_cast(m_read), error_to_report, false); m_read = 0; m_read_buffer_size = 0; m_read_buffer.clear(); } -void utp_socket_impl::maybe_trigger_send_callback() +void utp_socket_impl::maybe_trigger_send_callback(error_code const& ec) { INVARIANT_CHECK; - // nothing has been written or there's no outstanding write operation - if (m_written == 0 || m_write_handler == false) return; + if (m_write_handler == false) return; + + // nothing has been written + if (m_written == 0 && !ec) return; UTP_LOGV("%8p: calling write handler written:%d\n", static_cast(this), m_written); m_write_handler = false; - utp_stream::on_write(m_userdata, aux::numeric_cast(m_written), m_error, false); + error_code const error_to_report = ec ? ec : m_error; + utp_stream::on_write(m_userdata, aux::numeric_cast(m_written), error_to_report, false); m_written = 0; m_write_buffer_size = 0; m_write_buffer.clear(); + if (m_out_eof + && !m_nagle_packet + && state() == state_t::connected) + send_fin(); +} + +void utp_socket_impl::maybe_trigger_writeable_callback(error_code const& ec) +{ + INVARIANT_CHECK; + + if (m_writeable_handler == false) return; + + if (m_stalled) return; + + m_writeable_handler = false; + error_code const error_to_report = ec ? ec : m_error; + utp_stream::on_writeable(m_userdata, error_to_report); } void utp_socket_impl::set_close_reason(close_reason_t code) @@ -833,6 +905,23 @@ void utp_socket_impl::set_close_reason(close_reason_t code) m_close_reason = code; } +void utp_socket_impl::close() +{ +#if TORRENT_UTP_LOG + UTP_LOGV("%8p: client closing socket\n", static_cast(this)); +#endif + // the FIN packet is supposed to be last, so if we still have user data + // waiting to be sent, we have to defer sending the FIN + m_out_eof = true; + maybe_trigger_send_callback(boost::asio::error::eof); + + if (!m_nagle_packet + && m_write_buffer_size == 0 + && state() == state_t::connected + && m_outbuf.at(m_seq_nr) == nullptr) + send_fin(); +} + bool utp_socket_impl::destroy() { INVARIANT_CHECK; @@ -844,8 +933,7 @@ bool utp_socket_impl::destroy() if (m_userdata == nullptr) return false; - if (state() == state_t::connected) - send_fin(); + close(); bool cancelled = cancel_handlers(boost::asio::error::operation_aborted, true); @@ -868,8 +956,6 @@ bool utp_socket_impl::destroy() } return cancelled; - - // #error our end is closing. Wait for everything to be acked } void utp_socket_impl::detach() @@ -976,35 +1062,59 @@ void utp_socket_impl::writable() #endif TORRENT_ASSERT(m_stalled); m_stalled = false; + maybe_trigger_writeable_callback({}); if (should_delete()) return; - // this handles the case where send_fin() was called while stalled - if (state() == state_t::fin_sent && m_outbuf.at(m_seq_nr) == nullptr) - send_pkt(pkt_fin); // if the socket stalled while sending an ack then there will be a // pending deferred ack. make sure it gets sent out else if (!m_deferred_ack || send_pkt(pkt_ack)) while(send_pkt()); - maybe_trigger_send_callback(); + // try to flush the last part of the send buffer before sending a FIN + if (m_out_eof && m_nagle_packet) send_pkt(); + + // this handles the case where send_fin() was called while stalled + if (m_out_eof + && !m_nagle_packet + && m_write_buffer_size == 0 + && state() == state_t::connected + && m_outbuf.at(m_seq_nr) == nullptr) + send_fin(); + + maybe_trigger_send_callback({}); } void utp_socket_impl::send_fin() { INVARIANT_CHECK; + TORRENT_ASSERT(m_write_buffer_size == 0); + TORRENT_ASSERT(m_out_eof); + TORRENT_ASSERT(!m_nagle_packet); + send_pkt(pkt_fin); // unless there was an error, we're now // in FIN-SENT state if (!m_error) + { set_state(state_t::fin_sent); + } + else + { +#if TORRENT_UTP_LOG + UTP_LOGV("%8p: send_fin error:%s\n", static_cast(this) + , m_error.message().c_str()); +#endif + set_state(state_t::error_wait); + test_socket_state(); + } #if TORRENT_UTP_LOG UTP_LOGV("%8p: state:%s\n", static_cast(this), socket_state_names[m_state]); #endif } -void utp_socket_impl::send_reset(utp_header const* ph) +void utp_socket_impl::send_reset(std::uint16_t const ack_nr) { INVARIANT_CHECK; @@ -1015,13 +1125,13 @@ void utp_socket_impl::send_reset(utp_header const* ph) h.timestamp_difference_microseconds = m_reply_micro; h.wnd_size = 0; h.seq_nr = std::uint16_t(random(0xffff)); - h.ack_nr = ph->seq_nr; + h.ack_nr = ack_nr; time_point const now = clock_type::now(); h.timestamp_microseconds = std::uint32_t( total_microseconds(now.time_since_epoch()) & 0xffffffff); UTP_LOGV("%8p: send_reset seq_nr:%d id:%d ack_nr:%d\n" - , static_cast(this), int(h.seq_nr), int(m_send_id), int(ph->seq_nr)); + , static_cast(this), int(h.seq_nr), int(m_send_id), int(ack_nr)); // ignore errors here error_code ec; @@ -1343,9 +1453,14 @@ bool utp_socket_impl::send_pkt(int const flags) return false; } - bool const force = (flags & pkt_ack) || (flags & pkt_fin); + // m_out_eof means we're trying to close the write side of this socket, + // we need to flush all payload before we can send the FIN packet, so don't + // store any payload in the nagle packet + bool const force = (flags & pkt_ack) || (flags & pkt_fin) || m_out_eof; -// TORRENT_ASSERT(state() != state_t::fin_sent || (flags & pkt_ack)); + // when we want to close the outgoing stream, we need to send the + // remaining nagle packet even though it won't fill a packet. + bool const force_flush_nagle = m_out_eof && m_write_buffer_size; // first see if we need to resend any packets @@ -1412,24 +1527,23 @@ bool utp_socket_impl::send_pkt(int const flags) // although, we may re-send packets, but those live in m_outbuf TORRENT_ASSERT(state() != state_t::fin_sent || m_write_buffer_size == 0); - // If the connection is finalizing we no longer want to include any payload - bool const finalizing = state() == state_t::fin_sent || (flags & pkt_fin); + int const nagle_size = m_nagle_packet ? m_nagle_packet->size - m_nagle_packet->header_size : 0; + int payload_size = std::min(m_write_buffer_size + nagle_size, effective_mtu - header_size); - int payload_size = finalizing ? 0 : std::min(m_write_buffer_size - , effective_mtu - header_size); TORRENT_ASSERT(payload_size >= 0); + // we cannot include any payload in FIN packets + TORRENT_ASSERT((flags & pkt_fin) == 0 || payload_size == 0); + // if we have one MSS worth of data, make sure it fits in our // congestion window and the advertised receive window from // the other end. if (m_bytes_in_flight + payload_size > std::min(int(m_cwnd >> 16) , int(m_adv_wnd))) { - // this means there's not enough room in the send window for - // another packet. We have to hold off sending this data. - // we still need to send an ACK though - // if we're trying to send a FIN, make an exception - if ((flags & pkt_fin) == 0) payload_size = 0; + // we can't fit a full packet of payload in the cwnd, but if + // we're sending an ACK, we can send a packet without payload + if (flags & pkt_ack) payload_size = 0; // we're constrained by the window size m_cwnd_full = true; @@ -1456,7 +1570,7 @@ bool utp_socket_impl::send_pkt(int const flags) // if we don't have any data to send, or can't send any data // and we don't have any data to force, don't send a packet - if (payload_size == 0 && !force && !m_nagle_packet) + if (payload_size == 0 && !force) { #if TORRENT_UTP_LOG UTP_LOGV("%8p: skipping send (no payload and no force) seq_nr:%d ack_nr:%d " @@ -1477,10 +1591,11 @@ bool utp_socket_impl::send_pkt(int const flags) // payload size being zero means we're just sending // an force. For efficiency, pick up the nagle packet // if there's room - if (!m_nagle_packet || finalizing || (payload_size == 0 && force - && m_bytes_in_flight + m_nagle_packet->size - > std::min(int(m_cwnd >> 16), int(m_adv_wnd)))) + // note that if there is a nagle packet, payload_size will include its + // size, so we won't take the first branch here + if (!m_nagle_packet || (payload_size == 0 && force && m_cwnd_full)) { + TORRENT_ASSERT(!(force_flush_nagle && m_nagle_packet)); p = acquire_packet(effective_mtu); if (payload_size) @@ -1516,10 +1631,12 @@ bool utp_socket_impl::send_pkt(int const flags) { #if TORRENT_UTP_LOG if (payload_size == 0 && force) - UTP_LOGV("%8p: Picking up Nagled packet due to forced send\n" - , static_cast(this)); + UTP_LOGV("%8p: Picking up Nagled packet due to forced send (%d bytes)\n" + , static_cast(this), m_nagle_packet->size); #endif + TORRENT_ASSERT(state() != state_t::fin_sent); + // pick up the nagle packet and keep adding bytes to it p = std::move(m_nagle_packet); m_nagle_packet.reset(); @@ -1575,10 +1692,6 @@ bool utp_socket_impl::send_pkt(int const flags) m_nagle_packet = std::move(p); return false; } - -#if TORRENT_USE_ASSERTS - payload_size = p->size - p->header_size; -#endif } if (sack) @@ -1599,6 +1712,7 @@ bool utp_socket_impl::send_pkt(int const flags) if (m_bytes_in_flight > 0 && int(p->size) < std::min(int(p->allocated), effective_mtu) + && !force_flush_nagle && !force && m_nagle && compare_less_wrap(m_acked_seq_nr, m_nagle_seq_nr, ACK_MASK)) @@ -1732,6 +1846,7 @@ bool utp_socket_impl::send_pkt(int const flags) , static_cast(this)); #endif m_deferred_ack = false; + m_sm.cancel_deferred_ack(this); } } @@ -1770,6 +1885,8 @@ bool utp_socket_impl::send_pkt(int const flags) release_packet(std::move(old)); } TORRENT_ASSERT(h->seq_nr == m_seq_nr); + // we shouldn't be sending payload at sequence numbers past the FIN + TORRENT_ASSERT(state() != state_t::fin_sent); m_seq_nr = (m_seq_nr + 1) & ACK_MASK; TORRENT_ASSERT(payload_size >= 0); if (!m_stalled) m_bytes_in_flight += new_in_flight; @@ -1779,11 +1896,26 @@ bool utp_socket_impl::send_pkt(int const flags) TORRENT_ASSERT(payload_size == 0); // If we're stalled we'll need to resend if (m_stalled) p->need_resend = true; - m_outbuf.insert(m_seq_nr, std::move(p)); + packet_ptr old = m_outbuf.insert(m_seq_nr, std::move(p)); + if (old) + { + if (!old->need_resend) m_bytes_in_flight -= old->size - old->header_size; + release_packet(std::move(old)); + } } else { TORRENT_ASSERT(h->seq_nr == m_seq_nr); + + // this is a re-entrant call, so we have to be careful only + // making it if we're not already sending a FIN + if (m_out_eof + && m_write_buffer_size == 0 + && !m_nagle_packet + && state() == state_t::connected) + { + send_fin(); + } } // if the socket is stalled, always return false, don't @@ -2152,15 +2284,18 @@ bool utp_socket_impl::cancel_handlers(error_code const& ec, bool shutdown) // calling the callbacks with m_userdata being 0 will just crash TORRENT_ASSERT((ret && m_userdata != nullptr) || !ret); - bool read = m_read_handler; - bool write = m_write_handler; - bool connect = m_connect_handler; + bool const read = m_read_handler; + bool const write = m_write_handler; + bool const writeable = m_writeable_handler; + bool const connect = m_connect_handler; m_read_handler = false; m_write_handler = false; + m_writeable_handler = false; m_connect_handler = false; if (read) utp_stream::on_read(m_userdata, 0, ec, shutdown); if (write) utp_stream::on_write(m_userdata, 0, ec, shutdown); + if (writeable) utp_stream::on_writeable(m_userdata, ec); if (connect) utp_stream::on_connect(m_userdata, ec, shutdown); return ret; } @@ -2173,7 +2308,7 @@ bool utp_socket_impl::consume_incoming_data( if (ph->get_type() != ST_DATA) return false; - if (m_eof && m_ack_nr == m_eof_seq_nr) + if (m_in_eof && m_ack_nr == m_in_eof_seq_nr) { // What?! We've already received a FIN and everything up // to it has been acked. Ignore this packet @@ -2425,6 +2560,9 @@ bool utp_socket_impl::incoming_packet(span b , static_cast(this), m_reply_micro, prev_base ? base_change : 0); } + bool const state_or_fin = ph->get_type() == ST_STATE + || ph->get_type() == ST_FIN; + // is this ACK valid? If the other end is ACKing // a packet that hasn't been sent yet // just ignore it. A 3rd party could easily inject a packet @@ -2437,8 +2575,10 @@ bool utp_socket_impl::incoming_packet(span b // and the ack_nr should be ignored // Note that when we send a FIN, we don't increment m_seq_nr std::uint16_t const cmp_seq_nr = - ((state() == state_t::syn_sent || state() == state_t::fin_sent) - && (ph->get_type() == ST_STATE || ph->get_type() == ST_FIN)) + ((state() == state_t::syn_sent + || state() == state_t::fin_sent + || state() == state_t::deleting) + && state_or_fin) ? m_seq_nr : (m_seq_nr - 1) & ACK_MASK; if ((state() != state_t::none || ph->get_type() != ST_SYN) @@ -2453,38 +2593,17 @@ bool utp_socket_impl::incoming_packet(span b return true; } - // check to make sure the sequence number of this packet - // is reasonable. If it's a data packet and we've already - // received it, ignore it. This is either a stray old packet - // that finally made it here (after having been re-sent) or - // an attempt to interfere with the connection from a 3rd party - // in both cases, we can safely ignore the timestamp and ACK - // information in this packet -/* - // even if we've already received this packet, we need to - // send another ack to it, since it may be a resend caused by - // our ack getting dropped - if (state() != state_t::syn_sent - && ph->get_type() == ST_DATA - && !compare_less_wrap(m_ack_nr, ph->seq_nr, ACK_MASK)) - { - // we've already received this packet - UTP_LOGV("%8p: incoming packet seq_nr:%d our ack_nr:%d (ignored)\n" - , static_cast(this), int(ph->seq_nr), m_ack_nr); - m_sm.inc_stats_counter(counters::utp_redundant_pkts_in); - return true; - } -*/ - // if the socket is closing, always ignore any packet // with a higher sequence number than the FIN sequence number - // ST_STATE messages always include the next seqnr. - if (m_eof && (compare_less_wrap(m_eof_seq_nr, ph->seq_nr, ACK_MASK) - || (m_eof_seq_nr == ph->seq_nr && ph->get_type() != ST_STATE))) + // ST_STATE messages always include the next seqnr, so it's acceptable to + // receive the same seq_nr as the EOF as long as it's a STATE or FIN packet + if (m_in_eof + && compare_less_wrap(m_in_eof_seq_nr, ph->seq_nr, ACK_MASK) + && !(m_in_eof_seq_nr == ph->seq_nr && state_or_fin)) { #if TORRENT_UTP_LOG - UTP_LOG("%8p: ERROR: incoming packet type: %s seq_nr:%d eof_seq_nr:%d (ignored)\n" - , static_cast(this), packet_type_names[ph->get_type()], int(ph->seq_nr), m_eof_seq_nr); + UTP_LOG("%8p: ERROR: incoming payload after FIN type: %s seq_nr:%d eof_seq_nr:%d (ignored)\n" + , static_cast(this), packet_type_names[ph->get_type()], int(ph->seq_nr), m_in_eof_seq_nr); #endif return true; } @@ -2645,10 +2764,6 @@ bool utp_socket_impl::incoming_packet(span b UTP_LOGV("%8p: updating timeout to: now + %d\n" , static_cast(this), packet_timeout()); - // the send operation in parse_sack() may have set the socket to an error - // state, in which case we shouldn't continue - if (state() == state_t::error_wait || state() == state_t::deleting) return true; - if (m_duplicate_acks >= dup_ack_limit && ((m_acked_seq_nr + 1) & ACK_MASK) == m_fast_resend_seq_nr) { @@ -2670,7 +2785,6 @@ bool utp_socket_impl::incoming_packet(span b // signal congestion if (!p->mtu_probe) experienced_loss(m_fast_resend_seq_nr, receive_time); resend_packet(p, true); - if (state() == state_t::error_wait || state() == state_t::deleting) return true; } } @@ -2698,37 +2812,47 @@ bool utp_socket_impl::incoming_packet(span b // The FIN arrived in order, nothing else is in the // reorder buffer. - -// TORRENT_ASSERT(m_inbuf.size() == 0); m_ack_nr = ph->seq_nr; + } + else + { + UTP_LOGV("%8p: FIN received out-of-order\n", static_cast(this)); + } - // Transition to state_t::fin_sent. The sent FIN is also an ack - // to the FIN we received. Once we're in state_t::fin_sent we - // just need to wait for our FIN to be acked. - - if (state() == state_t::fin_sent) - { - send_pkt(pkt_ack); - if (state() == state_t::error_wait || state() == state_t::deleting) return true; - } - else - { - send_fin(); - if (state() == state_t::error_wait || state() == state_t::deleting) return true; - } + if (payload_size > 0) + { + UTP_LOGV("%8p: FIN packet carries payload, which is not allowed (%d bytes)\n" + , static_cast(this), payload_size); } - if (m_eof) + if (m_in_eof) { - UTP_LOGV("%8p: duplicate FIN packet (ignoring)\n", static_cast(this)); - return true; + UTP_LOGV("%8p: duplicate FIN packet (not updating, m_in_eof_seq_nr=%d)\n" + , static_cast(this), m_in_eof_seq_nr); } - m_eof = true; - m_eof_seq_nr = ph->seq_nr; + else + { + m_in_eof = true; + // even though invalid, tolerate FIN packets with payload + if (payload_size > 0) + m_in_eof_seq_nr = (ph->seq_nr + 1) & ACK_MASK; + else + m_in_eof_seq_nr = ph->seq_nr; + UTP_LOGV("%8p: in_eof_seq_nr=%d m_receive_buffer=%d\n" + , static_cast(this), m_in_eof_seq_nr, int(m_receive_buffer.size())); + } + + defer_ack(); - // we will respond with a fin once we have received everything up to m_eof_seq_nr + if (m_ack_nr == m_in_eof_seq_nr && m_receive_buffer.empty()) + maybe_trigger_receive_callback(boost::asio::error::eof); + return true; } + // the send operation in parse_sack() may have set the socket to an error + // state, in which case we shouldn't continue + if (state() == state_t::error_wait || state() == state_t::deleting) return true; + switch (state()) { case state_t::none: @@ -2802,7 +2926,6 @@ bool utp_socket_impl::incoming_packet(span b // notify the client that the socket connected if (m_connect_handler) { - UTP_LOGV("%8p: calling connect handler\n", static_cast(this)); m_connect_handler = false; utp_stream::on_connect(m_userdata, m_error, false); } @@ -2838,7 +2961,10 @@ bool utp_socket_impl::incoming_packet(span b // space left in our send window or not. If we just got an ACK // (i.e. ST_STATE) we're not ACKing anything. If we just // received a FIN packet, we need to ack that as well - bool has_ack = ph->get_type() == ST_DATA || ph->get_type() == ST_FIN || ph->get_type() == ST_SYN; + bool const has_ack = ph->get_type() == ST_DATA + || ph->get_type() == ST_FIN + || ph->get_type() == ST_SYN; + std::uint32_t prev_out_packets = m_out_packets; // the connection is connected and this packet made it past all the @@ -2866,14 +2992,10 @@ bool utp_socket_impl::incoming_packet(span b if (state() == state_t::error_wait || state() == state_t::deleting) return true; - // Everything up to the FIN has been received, respond with a FIN - // from our side. - if (m_eof && m_ack_nr == ((m_eof_seq_nr - 1) & ACK_MASK)) + // Everything up to the FIN has been received + if (m_in_eof && m_ack_nr == ((m_in_eof_seq_nr - 1) & ACK_MASK)) { - UTP_LOGV("%8p: incoming stream consumed\n", static_cast(this)); - - // This transitions to the state_t::fin_sent state. - send_fin(); + UTP_LOGV("%8p: incoming stream at EOF\n", static_cast(this)); if (state() == state_t::error_wait || state() == state_t::deleting) return true; } @@ -2969,10 +3091,10 @@ bool utp_socket_impl::incoming_packet(span b // There are two ways we can end up in this state: // // 1. If the socket has been explicitly closed on our - // side, in which case m_eof is false. + // side, in which case m_in_eof is false. // // 2. If we received a FIN from the remote side, in which - // case m_eof is true. If this is the case, we don't + // case m_in_eof is true. If this is the case, we don't // come here until everything up to the FIN has been // received. // @@ -3065,7 +3187,7 @@ bool utp_socket_impl::incoming_packet(span b case state_t::error_wait: { // respond with a reset - send_reset(ph); + send_reset(ph->seq_nr); break; } } @@ -3222,9 +3344,11 @@ void utp_socket_impl::tick(time_point const now) INVARIANT_CHECK; #if TORRENT_UTP_LOG - UTP_LOGV("%8p: tick:%s r: %d (%s) w: %d (%s)\n" - , static_cast(this), socket_state_names[m_state], m_read, m_read_handler ? "handler" : "no handler" - , m_written, m_write_handler ? "handler" : "no handler"); + UTP_LOGV("%8p: tick:%s r: %d (%s) w: %d (%s) connect: (%s)\n" + , static_cast(this), socket_state_names[m_state], m_read + , m_read_handler ? "handler" : "no handler" + , m_written, m_write_handler ? "handler" : "no handler" + , m_connect_handler ? "handler" : "no handler"); #endif TORRENT_ASSERT(m_outbuf.at((m_acked_seq_nr + 1) & ACK_MASK) || ((m_seq_nr - m_acked_seq_nr) & ACK_MASK) <= 1); @@ -3435,6 +3559,8 @@ void utp_socket_impl::check_invariant() const { // if this packet is full, it should have been sent TORRENT_ASSERT(m_nagle_packet->size < m_nagle_packet->allocated); + + TORRENT_ASSERT(state() != state_t::fin_sent); } } #endif diff --git a/3rd/libtorrent-rasterbar/src/web_peer_connection.cpp b/3rd/libtorrent-rasterbar/src/web_peer_connection.cpp index bea47f8f..d2a47a2a 100644 --- a/3rd/libtorrent-rasterbar/src/web_peer_connection.cpp +++ b/3rd/libtorrent-rasterbar/src/web_peer_connection.cpp @@ -116,7 +116,7 @@ web_peer_connection::web_peer_connection(peer_connection_args& pack if (!m_url.empty() && m_url[m_url.size() - 1] == '/') { - m_url += escape_file_path(t->torrent_file().files(), file_index_t(0)); + m_url += escape_file_path(t->torrent_file().orig_files(), file_index_t(0)); } } @@ -280,7 +280,7 @@ void web_peer_connection::disconnect(error_code const& ec if (t) t->add_redundant_bytes(int(m_web->restart_piece.size()) , waste_reason::piece_closing); } - m_web->restart_piece.swap(m_piece); + m_web->restart_piece = std::move(m_piece); // we have to do this to not count this data as redundant. The // upper layer will call downloading_piece_progress and assume @@ -303,7 +303,8 @@ void web_peer_connection::disconnect(error_code const& ec } peer_connection::disconnect(ec, op, error); - if (t) t->disconnect_web_seed(this); + TORRENT_ASSERT(m_web->resolving == false); + m_web->peer_info.connection = nullptr; } piece_block_progress web_peer_connection::downloading_piece_progress() const @@ -359,13 +360,16 @@ void web_peer_connection::write_request(peer_request const& r) { int request_offset = r.start + r.length - size; pr.start = request_offset % piece_size; - pr.length = std::min(block_size, size); + pr.length = std::min(std::min(block_size, size), piece_size - pr.start); pr.piece = piece_index_t(static_cast(r.piece) + request_offset / piece_size); + TORRENT_ASSERT(validate_piece_request(pr)); m_requests.push_back(pr); if (m_web->restart_request == m_requests.front()) { - m_piece.swap(m_web->restart_piece); + TORRENT_ASSERT(int(m_piece.size()) == m_received_in_piece); + TORRENT_ASSERT(m_piece.empty()); + m_piece = std::move(m_web->restart_piece); peer_request const& front = m_requests.front(); TORRENT_ASSERT(front.length > int(m_piece.size())); @@ -385,6 +389,8 @@ void web_peer_connection::write_request(peer_request const& r) // it doesn't know we just re-wrote the request incoming_piece_fragment(int(m_piece.size())); m_web->restart_request.piece = piece_index_t(-1); + + TORRENT_ASSERT(int(m_piece.size()) == m_received_in_piece); } #if 0 @@ -635,6 +641,21 @@ void web_peer_connection::handle_error(int const bytes_left) disconnect(error_code(m_parser.status_code(), http_category()), operation_t::bittorrent, failure); } +void web_peer_connection::disable(error_code const& ec) +{ + // we should not try this server again. + m_web->disabled = true; + disconnect(ec, operation_t::bittorrent, peer_error); + if (m_web->ephemeral) + { + std::shared_ptr t = associated_torrent().lock(); + TORRENT_ASSERT(t); + t->remove_web_seed_conn(this); + } + m_web = nullptr; + TORRENT_ASSERT(is_disconnecting()); +} + void web_peer_connection::handle_redirect(int const bytes_left) { // this means we got a redirection request @@ -647,10 +668,7 @@ void web_peer_connection::handle_redirect(int const bytes_left) if (location.empty()) { - // we should not try this server again. - t->remove_web_seed_conn(this, errors::missing_location, operation_t::bittorrent, peer_error); - m_web = nullptr; - TORRENT_ASSERT(is_disconnecting()); + disable(errors::missing_location); return; } @@ -902,10 +920,7 @@ void web_peer_connection::on_receive(error_code const& error if (ec) { received_bytes(0, int(recv_buffer.size())); - // we should not try this server again. - t->remove_web_seed_conn(this, ec, operation_t::bittorrent, peer_error); - m_web = nullptr; - TORRENT_ASSERT(is_disconnecting()); + disable(ec); return; } @@ -1089,7 +1104,11 @@ void web_peer_connection::incoming_payload(char const* buf, int len) // deliver all complete bittorrent requests to the bittorrent engine while (len > 0) { - if (m_requests.empty()) return; + if (m_requests.empty()) + { + TORRENT_ASSERT(m_piece.empty()); + return; + } TORRENT_ASSERT(!m_requests.empty()); peer_request const& front_request = m_requests.front(); @@ -1098,6 +1117,7 @@ void web_peer_connection::incoming_payload(char const* buf, int len) // m_piece may not hold more than the response to the next BT request TORRENT_ASSERT(front_request.length > piece_size); + TORRENT_ASSERT(int(m_piece.size()) == m_received_in_piece); // copy_size is the number of bytes we need to add to the end of m_piece // to not exceed the size of the next bittorrent request to be delivered. @@ -1111,28 +1131,7 @@ void web_peer_connection::incoming_payload(char const* buf, int len) incoming_piece_fragment(copy_size); TORRENT_ASSERT(front_request.length >= piece_size); - if (int(m_piece.size()) == front_request.length) - { - std::shared_ptr t = associated_torrent().lock(); - TORRENT_ASSERT(t); - -#ifndef TORRENT_DISABLE_LOGGING - peer_log(peer_log_alert::incoming_message, "POP_REQUEST" - , "piece: %d start: %d len: %d" - , static_cast(front_request.piece), front_request.start, front_request.length); -#endif - - // Make a copy of the request and pop it off the queue before calling - // incoming_piece because that may lead to a call to disconnect() - // which will clear the request queue and invalidate any references - // to the request - peer_request const front_request_copy = front_request; - m_requests.pop_front(); - - incoming_piece(front_request_copy, m_piece.data()); - - m_piece.clear(); - } + maybe_harvest_piece(); } } @@ -1168,6 +1167,8 @@ void web_peer_connection::incoming_zeroes(int len) void web_peer_connection::maybe_harvest_piece() { + TORRENT_ASSERT(!m_requests.empty()); + peer_request const& front_request = m_requests.front(); TORRENT_ASSERT(front_request.length >= int(m_piece.size())); if (int(m_piece.size()) != front_request.length) return; @@ -1181,9 +1182,10 @@ void web_peer_connection::maybe_harvest_piece() , static_cast(front_request.piece) , front_request.start, front_request.length); #endif + peer_request const req = m_requests.front(); m_requests.pop_front(); - incoming_piece(front_request, m_piece.data()); + incoming_piece(req, m_piece.data()); m_piece.clear(); } diff --git a/3rd/libtorrent-rasterbar/src/write_resume_data.cpp b/3rd/libtorrent-rasterbar/src/write_resume_data.cpp index 208fd21f..bed5de74 100644 --- a/3rd/libtorrent-rasterbar/src/write_resume_data.cpp +++ b/3rd/libtorrent-rasterbar/src/write_resume_data.cpp @@ -107,6 +107,9 @@ namespace { ret["auto_managed"] = bool(atp.flags & torrent_flags::auto_managed); #ifndef TORRENT_DISABLE_SUPERSEEDING ret["super_seeding"] = bool(atp.flags & torrent_flags::super_seeding); +#endif +#if TORRENT_USE_I2P + ret["i2p"] = bool(atp.flags & torrent_flags::i2p_torrent); #endif ret["sequential_download"] = bool(atp.flags & torrent_flags::sequential_download); ret["stop_when_ready"] = bool(atp.flags & torrent_flags::stop_when_ready); @@ -331,8 +334,7 @@ namespace { if (fs.pad_file_at(f) || fs.file_size(f) <= fs.piece_length()) continue; - aux::merkle_tree t(fs.file_num_blocks(f) - , fs.piece_length() / default_block_size, fs.root_ptr(f)); + aux::merkle_tree t(fs.file_num_blocks(f), fs.blocks_per_piece(), fs.root_ptr(f)); std::vector const& verified = (f >= atp.verified_leaf_hashes.end_index()) ? empty_verified : atp.verified_leaf_hashes[f]; diff --git a/3rd/libtorrent-rasterbar/test/main.cpp b/3rd/libtorrent-rasterbar/test/main.cpp index 0d4dc915..59c5fc69 100644 --- a/3rd/libtorrent-rasterbar/test/main.cpp +++ b/3rd/libtorrent-rasterbar/test/main.cpp @@ -134,7 +134,7 @@ LONG WINAPI seh_exception_handler(LPEXCEPTION_POINTERS p) strcpy(stack_text, ""); #endif - int const code = p->ExceptionRecord->ExceptionCode; + DWORD const code = p->ExceptionRecord->ExceptionCode; char const* name = ""; switch (code) { @@ -462,26 +462,7 @@ int EXPORT main(int argc, char const* argv[]) // redirect test output to a temporary file fflush(stdout); fflush(stderr); - -#ifdef TORRENT_MINGW - // mingw has a buggy tmpfile() and tmpname() that needs a . prepended - // to it (or some other directory) - char temp_name[512]; - FILE* f = nullptr; - if (tmpnam_s(temp_name + 1, sizeof(temp_name) - 1) == 0) - { - temp_name[0] = '.'; - std::printf("using temporary filename %s\n", temp_name); - f = fopen(temp_name, "wb+"); - } - else - { - std::printf("failed to generate filename for redirecting " - "output: (%d) %s\n", errno, strerror(errno)); - } -#else FILE* f = tmpfile(); -#endif if (f != nullptr) { int ret1 = 0; diff --git a/3rd/libtorrent-rasterbar/test/setup_transfer.cpp b/3rd/libtorrent-rasterbar/test/setup_transfer.cpp index 62762cba..ff32dc60 100644 --- a/3rd/libtorrent-rasterbar/test/setup_transfer.cpp +++ b/3rd/libtorrent-rasterbar/test/setup_transfer.cpp @@ -220,11 +220,13 @@ bool supports_ipv6() #if defined TORRENT_BUILD_SIMULATOR return true; #elif defined TORRENT_WINDOWS - TORRENT_TRY { + try + { error_code ec; make_address("::1", ec); return !ec; - } TORRENT_CATCH(std::exception const&) { return false; } + } + catch (std::exception const&) { return false; } #else io_context ios; tcp::socket test(ios); diff --git a/3rd/libtorrent-rasterbar/test/test_alert_types.cpp b/3rd/libtorrent-rasterbar/test/test_alert_types.cpp index 01a2d06d..7c71a8b3 100644 --- a/3rd/libtorrent-rasterbar/test/test_alert_types.cpp +++ b/3rd/libtorrent-rasterbar/test/test_alert_types.cpp @@ -184,10 +184,15 @@ TORRENT_TEST(alerts_types) TEST_ALERT_TYPE(file_prio_alert, 97, alert_priority::normal, alert_category::storage); TEST_ALERT_TYPE(oversized_file_alert, 98, alert_priority::normal, alert_category::storage); TEST_ALERT_TYPE(torrent_conflict_alert, 99, alert_priority::high, alert_category::error); + TEST_ALERT_TYPE(peer_info_alert, 100, alert_priority::critical, alert_category::status); + TEST_ALERT_TYPE(file_progress_alert, 101, alert_priority::critical, alert_category::file_progress); + TEST_ALERT_TYPE(piece_info_alert, 102, alert_priority::critical, alert_category::piece_progress); + TEST_ALERT_TYPE(piece_availability_alert, 103, alert_priority::critical, alert_category::status); + TEST_ALERT_TYPE(tracker_list_alert, 104, alert_priority::critical, alert_category::status); #undef TEST_ALERT_TYPE - TEST_EQUAL(num_alert_types, 100); + TEST_EQUAL(num_alert_types, 105); TEST_EQUAL(num_alert_types, count_alert_types); } diff --git a/3rd/libtorrent-rasterbar/test/test_create_torrent.cpp b/3rd/libtorrent-rasterbar/test/test_create_torrent.cpp index 4125a5b3..92982d38 100644 --- a/3rd/libtorrent-rasterbar/test/test_create_torrent.cpp +++ b/3rd/libtorrent-rasterbar/test/test_create_torrent.cpp @@ -291,6 +291,7 @@ TORRENT_TEST(v2_only_set_hash) TEST_THROW(t.set_hash(0_piece, lt::sha1_hash::max())); } +#if TORRENT_HAS_SYMLINK || !defined TORRENT_WINDOWS namespace { void check(int ret) @@ -302,6 +303,7 @@ void check(int ret) } } +#endif #if TORRENT_HAS_SYMLINK diff --git a/3rd/libtorrent-rasterbar/test/test_dht.cpp b/3rd/libtorrent-rasterbar/test/test_dht.cpp index 9b112391..9cd566c2 100644 --- a/3rd/libtorrent-rasterbar/test/test_dht.cpp +++ b/3rd/libtorrent-rasterbar/test/test_dht.cpp @@ -3370,6 +3370,7 @@ TORRENT_TEST(rpc_invalid_error_msg) #if TORRENT_USE_ASSERTS o->m_in_constructor = false; #endif + o->flags |= observer::flag_queried; rpc.invoke(req, source, o); // here's the incoming (malformed) error message diff --git a/3rd/libtorrent-rasterbar/test/test_enum_net.cpp b/3rd/libtorrent-rasterbar/test/test_enum_net.cpp index c2548211..de0895c8 100644 --- a/3rd/libtorrent-rasterbar/test/test_enum_net.cpp +++ b/3rd/libtorrent-rasterbar/test/test_enum_net.cpp @@ -50,6 +50,10 @@ TORRENT_TEST(is_local) TEST_CHECK(!ec); TEST_CHECK(is_local(make_address("10.1.1.56", ec))); TEST_CHECK(!ec); + TEST_CHECK(is_local(make_address("100.64.0.0", ec))); + TEST_CHECK(!ec); + TEST_CHECK(is_local(make_address("100.127.255.255", ec))); + TEST_CHECK(!ec); TEST_CHECK(!is_local(make_address("14.14.251.63", ec))); TEST_CHECK(!ec); } diff --git a/3rd/libtorrent-rasterbar/test/test_hash_picker.cpp b/3rd/libtorrent-rasterbar/test/test_hash_picker.cpp index b96428c0..8ea3326c 100644 --- a/3rd/libtorrent-rasterbar/test/test_hash_picker.cpp +++ b/3rd/libtorrent-rasterbar/test/test_hash_picker.cpp @@ -44,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. using namespace lt; +#if 0 struct mock_peer_connection final : peer_connection_interface { tcp::endpoint const& remote() const override { return m_remote; } @@ -66,6 +67,18 @@ struct mock_peer_connection final : peer_connection_interface void peer_log(peer_log_alert::direction_t , char const*, char const*, ...) const noexcept override TORRENT_FORMAT(4, 5) {} #endif +#if TORRENT_USE_I2P + std::string const& destination() const override + { + static std::string const empty; + return empty; + } + std::string const& local_i2p_endpoint() const override + { + static std::string const empty; + return empty; + } +#endif torrent_peer* m_torrent_peer; lt::stat m_stat; @@ -73,7 +86,6 @@ struct mock_peer_connection final : peer_connection_interface peer_id m_pid; }; -#if 0 TORRENT_TEST(pick_piece_layer) { file_storage fs; diff --git a/3rd/libtorrent-rasterbar/test/test_magnet.cpp b/3rd/libtorrent-rasterbar/test/test_magnet.cpp index 6ded8794..97b043ed 100644 --- a/3rd/libtorrent-rasterbar/test/test_magnet.cpp +++ b/3rd/libtorrent-rasterbar/test/test_magnet.cpp @@ -362,6 +362,18 @@ TORRENT_TEST(parse_dht_node) } #endif +#if TORRENT_USE_I2P +TORRENT_TEST(parse_i2p_tracker) +{ + add_torrent_params p = parse_magnet_uri("magnet:?xt=urn:btih:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "&tr=https://test.i2p/announce"); + TEST_CHECK(p.flags & torrent_flags::i2p_torrent); + p = parse_magnet_uri("magnet:?xt=urn:btih:cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "&tr=https://test.com/announce"); + TEST_CHECK(!(p.flags & torrent_flags::i2p_torrent)); +} +#endif + TORRENT_TEST(make_magnet_uri) { // make_magnet_uri diff --git a/3rd/libtorrent-rasterbar/test/test_merkle_tree.cpp b/3rd/libtorrent-rasterbar/test/test_merkle_tree.cpp index 78abdf67..e6d58135 100644 --- a/3rd/libtorrent-rasterbar/test/test_merkle_tree.cpp +++ b/3rd/libtorrent-rasterbar/test/test_merkle_tree.cpp @@ -856,7 +856,10 @@ TORRENT_TEST(set_block_invalid_empty_tree) // the tree is complete, we know all hashes already. This is just // comparing the hash against what we have in the tree auto const result = t.set_block(block, rand_sha256()); - TEST_CHECK(std::get<0>(result) == aux::merkle_tree::set_block_result::unknown); + if (block == num_blocks - 1) + TEST_CHECK(std::get<0>(result) == aux::merkle_tree::set_block_result::hash_failed); + else + TEST_CHECK(std::get<0>(result) == aux::merkle_tree::set_block_result::unknown); TEST_CHECK(t.verified_leafs() == none_set(num_blocks)); } } diff --git a/3rd/libtorrent-rasterbar/test/test_peer_list.cpp b/3rd/libtorrent-rasterbar/test/test_peer_list.cpp index d2771bf3..d101fbf9 100644 --- a/3rd/libtorrent-rasterbar/test/test_peer_list.cpp +++ b/3rd/libtorrent-rasterbar/test/test_peer_list.cpp @@ -58,12 +58,10 @@ struct mock_peer_connection : peer_connection_interface , std::enable_shared_from_this { - mock_peer_connection(mock_torrent* tor, bool out, tcp::endpoint const& remote) + mock_peer_connection(mock_torrent* tor, bool out) : m_choked(false) , m_outgoing(out) , m_tp(nullptr) - , m_remote(remote) - , m_local(ep("127.0.0.1", 8080)) , m_our_id(nullptr) , m_disconnect_called(false) , m_torrent(*tor) @@ -71,6 +69,21 @@ struct mock_peer_connection aux::random_bytes(m_id); } + mock_peer_connection(mock_torrent* tor, bool out, tcp::endpoint const& remote) + : mock_peer_connection(tor, out) + { + m_remote = remote; + m_local = ep("127.0.0.1", 8080); + } + +#if TORRENT_USE_I2P + mock_peer_connection(mock_torrent* tor, bool out, std::string remote) + : mock_peer_connection(tor, out) + { + m_i2p_destination = std::move(remote); + } +#endif + virtual ~mock_peer_connection() = default; #if !defined TORRENT_DISABLE_LOGGING @@ -103,11 +116,26 @@ struct mock_peer_connection torrent_peer* m_tp; tcp::endpoint m_remote; tcp::endpoint m_local; +#if TORRENT_USE_I2P + std::string m_i2p_destination; + std::string m_local_i2p_endpoint; +#endif peer_id m_id; peer_id m_our_id; bool m_disconnect_called; mock_torrent& m_torrent; +#if TORRENT_USE_I2P + std::string const& destination() const override + { + return m_i2p_destination; + } + std::string const& local_i2p_endpoint() const override + { + return m_local_i2p_endpoint; + } +#endif + void get_peer_info(peer_info&) const override {} tcp::endpoint const& remote() const override { return m_remote; } tcp::endpoint local_endpoint() const override { return m_local; } @@ -190,6 +218,21 @@ torrent_peer* add_peer(peer_list& p, torrent_state& st, tcp::endpoint const& ep) return peer; } +#if TORRENT_USE_I2P +torrent_peer* add_i2p_peer(peer_list& p, torrent_state& st, std::string const& destination) +{ + int cc = p.num_connect_candidates(); + torrent_peer* peer = p.add_i2p_peer(destination, {}, {}, &st); + if (peer) + { + TEST_EQUAL(p.num_connect_candidates(), cc + 1); + TEST_EQUAL(peer->dest(), destination); + } + st.erased.clear(); + return peer; +} +#endif + void connect_peer(peer_list& p, mock_torrent& t, torrent_state& st) { torrent_peer* tp = p.connect_one_peer(0, &st); @@ -447,14 +490,14 @@ TORRENT_TEST(port_filter) // now, filter one of the IPs and make sure the peer is removed port_filter filter; filter.add_rule(9000, 10000, 1); - std::vector
        banned; + std::vector banned; p.apply_port_filter(filter, &st, banned); // we just erased a peer, because it was filtered by the ip filter TEST_EQUAL(st.erased.size(), 1); TEST_EQUAL(p.num_connect_candidates(), 0); TEST_EQUAL(p.num_peers(), 1); TEST_EQUAL(banned.size(), 1); - TEST_EQUAL(banned[0], addr4("11.0.0.2")); + TEST_EQUAL(banned[0], ep("11.0.0.2", 9020)); TEST_EQUAL(con2->was_disconnected(), true); TEST_EQUAL(con1->was_disconnected(), false); } @@ -566,7 +609,7 @@ TORRENT_TEST(set_ip_filter) TORRENT_TEST(set_port_filter) { torrent_state st = init_state(); - std::vector
        banned; + std::vector banned; mock_torrent t(&st); peer_list p(allocator); @@ -775,7 +818,7 @@ TORRENT_TEST(double_connection) p.new_connection(*con1, 0, &st); - // and the incoming connection + // the seconds incoming connection auto con2 = std::make_shared(&t, false, ep("10.0.0.2", 3561)); con2->set_local_ep(ep("10.0.0.1", 8080)); @@ -881,6 +924,126 @@ TORRENT_TEST(double_connection_win) TEST_EQUAL(con_in->was_disconnected(), true); } +#if TORRENT_USE_I2P +// test i2p self-connection +TORRENT_TEST(self_connection_i2p) +{ + torrent_state st = init_state(); + mock_torrent t(&st); + st.allow_multiple_connections_per_ip = false; + peer_list p(allocator); + t.m_p = &p; + + // add and connect peer + torrent_peer* peer = add_i2p_peer(p, st, "foobar"); + connect_peer(p, t, st); + + auto con_out = shared_from_this(peer->connection); + con_out->m_i2p_destination = "foobar"; + con_out->m_local_i2p_endpoint = "foobar"; + + auto con_in = std::make_shared(&t, false, "foobar"); + con_in->m_local_i2p_endpoint = "foobar"; + + p.new_connection(*con_in, 0, &st); + + // from the peer_list's point of view, this looks like we made one + // outgoing connection and received an incoming one. Since they share + // the exact same endpoints (IP ports) but just swapped source and + // destination, the peer list is supposed to figure out that we connected + // to ourself and disconnect it + TEST_EQUAL(con_out->was_disconnected(), true); + TEST_EQUAL(con_in->was_disconnected(), true); +} + +// test double i2p connection (both incoming) +TORRENT_TEST(double_connection_i2p) +{ + torrent_state st = init_state(); + mock_torrent t(&st); + st.allow_multiple_connections_per_ip = false; + peer_list p(allocator); + t.m_p = &p; + + // we are "foo" and the other peer is "bar" + + // first incoming connection + auto con1 = std::make_shared(&t, false, "bar"); + con1->m_local_i2p_endpoint = "foo"; + + p.new_connection(*con1, 0, &st); + + // the second incoming connection + auto con2 = std::make_shared(&t, false, "bar"); + con2->m_local_i2p_endpoint = "foo"; + + p.new_connection(*con2, 0, &st); + + // the second incoming connection should be closed + TEST_EQUAL(con1->was_disconnected(), false); + TEST_EQUAL(con2->was_disconnected(), true); +} + +// test double connection (we loose) +TORRENT_TEST(double_connection_loose_i2p) +{ + torrent_state st = init_state(); + mock_torrent t(&st); + st.allow_multiple_connections_per_ip = false; + peer_list p(allocator); + t.m_p = &p; + + // we are "foo" and the other peer is "bar" + + // our outgoing connection + torrent_peer* peer = add_i2p_peer(p, st, "bar"); + connect_peer(p, t, st); + + auto con_out = shared_from_this(peer->connection); + con_out->m_local_i2p_endpoint = "foo"; + + // and the incoming connection + auto con_in = std::make_shared(&t, false, "bar"); + con_in->m_local_i2p_endpoint = "foo"; + + p.new_connection(*con_in, 0, &st); + + // the rules are documented in peer_list.cpp + TEST_EQUAL(con_out->was_disconnected(), true); + TEST_EQUAL(con_in->was_disconnected(), false); +} + +// test double connection (we win) +TORRENT_TEST(double_connection_win_i2p) +{ + torrent_state st = init_state(); + mock_torrent t(&st); + st.allow_multiple_connections_per_ip = false; + peer_list p(allocator); + t.m_p = &p; + + // we are "bar" and the other peer is "foo" + // "bar" < "foo", so we gets to make the outgoing connection + + // our outgoing connection + torrent_peer* peer = add_i2p_peer(p, st, "foo"); + connect_peer(p, t, st); + + auto con_out = shared_from_this(peer->connection); + con_out->m_local_i2p_endpoint = "bar"; + + //and the incoming connection + auto con_in = std::make_shared(&t, false, "foo"); + con_in->m_local_i2p_endpoint = "bar"; + + p.new_connection(*con_in, 0, &st); + + // the rules are documented in peer_list.cpp + TEST_EQUAL(con_out->was_disconnected(), true); + TEST_EQUAL(con_in->was_disconnected(), false); +} +#endif + // test incoming connection when we are at the list size limit TORRENT_TEST(incoming_size_limit) { @@ -965,6 +1128,84 @@ TORRENT_TEST(new_peer_size_limit) , 5); } +TORRENT_TEST(peer_info_comparison) +{ + peer_address_compare cmp; + ipv4_peer const ip_low(ep("1.1.1.1", 6888), true, {}); + ipv4_peer const ip_high(ep("100.1.1.1", 6888), true, {}); + TEST_CHECK(cmp(&ip_low, &ip_high)); + TEST_CHECK(!cmp(&ip_high, &ip_low)); + TEST_CHECK(!cmp(&ip_high, &ip_high)); + TEST_CHECK(!cmp(&ip_low, &ip_low)); + + TEST_CHECK(!cmp(&ip_low, addr("1.1.1.1"))); + TEST_CHECK(cmp(&ip_low, addr("1.1.1.2"))); + TEST_CHECK(cmp(&ip_low, addr("100.1.1.1"))); + + TEST_CHECK(!cmp(addr("1.1.1.1"), &ip_low)); + TEST_CHECK(cmp(addr("1.1.1.0"), &ip_low)); + TEST_CHECK(!cmp( addr("100.1.1.1"), &ip_low)); + +#if TORRENT_USE_I2P + i2p_peer const i2p_low("aaaaaa", true, {}); + i2p_peer const i2p_high("zzzzzz", true, {}); + + // noremal IPs always sort before i2p addresses + TEST_CHECK(cmp(&ip_low, &i2p_high)); + TEST_CHECK(cmp(&ip_low, &i2p_low)); + TEST_CHECK(cmp(&ip_high, &i2p_high)); + TEST_CHECK(cmp(&ip_high, &i2p_low)); + + // i2p addresses always sort after noremal IPs + TEST_CHECK(!cmp(&i2p_high, &ip_low)); + TEST_CHECK(!cmp(&i2p_low, &ip_low)); + TEST_CHECK(!cmp(&i2p_high, &ip_high)); + TEST_CHECK(!cmp(&i2p_low, &ip_high)); + + // noremal IPs always sort before i2p addresses + TEST_CHECK(cmp(addr4("1.1.1.1"), &i2p_high)); + TEST_CHECK(cmp(addr4("1.1.1.1"), &i2p_low)); + TEST_CHECK(cmp(addr4("100.1.1.1"), &i2p_high)); + TEST_CHECK(cmp(addr4("100.1.1.1"), &i2p_low)); + + // i2p addresses always sort after noremal IPs + TEST_CHECK(!cmp(&i2p_high, addr4("1.1.1.1"))); + TEST_CHECK(!cmp(&i2p_low, addr4("1.1.1.1"))); + TEST_CHECK(!cmp(&i2p_high, addr4("100.1.1.1"))); + TEST_CHECK(!cmp(&i2p_low, addr4("100.1.1.1"))); + + // internal i2p sorting + TEST_CHECK(cmp(&i2p_low, &i2p_high)); + TEST_CHECK(!cmp(&i2p_high, &i2p_low)); + TEST_CHECK(!cmp(&i2p_high, &i2p_high)); + TEST_CHECK(!cmp(&i2p_low, &i2p_low)); + + TEST_CHECK(cmp(&i2p_low, "zzzzzz")); + TEST_CHECK(!cmp(&i2p_high, "aaaaaa")); + TEST_CHECK(!cmp(&i2p_high, "zzzzzz")); + TEST_CHECK(!cmp(&i2p_low, "aaaaaa")); + TEST_CHECK(cmp(&i2p_low, "aaaaab")); + + TEST_CHECK(cmp("aaaaaa", &i2p_high)); + TEST_CHECK(!cmp("zzzzzz", &i2p_low)); + TEST_CHECK(!cmp("zzzzzz", &i2p_high)); + TEST_CHECK(cmp("zzzzzy", &i2p_high)); + TEST_CHECK(!cmp("aaaaaa", &i2p_low)); +#endif +} + +#if TORRENT_USE_I2P +TORRENT_TEST(peer_info_set_i2p_destination) +{ + peer_info p; + TORRENT_ASSERT(!(p.flags & peer_info::i2p_socket)); + p.set_i2p_destination(sha256_hash("................................")); + + TORRENT_ASSERT(p.i2p_destination() == sha256_hash("................................")); + TORRENT_ASSERT(p.flags & peer_info::i2p_socket); +} +#endif + // TODO: test erasing peers // TODO: test update_peer_port with allow_multiple_connections_per_ip and without // TODO: test add i2p peers diff --git a/3rd/libtorrent-rasterbar/test/test_privacy.cpp b/3rd/libtorrent-rasterbar/test/test_privacy.cpp index 1e87cc79..60e989b7 100644 --- a/3rd/libtorrent-rasterbar/test/test_privacy.cpp +++ b/3rd/libtorrent-rasterbar/test/test_privacy.cpp @@ -339,10 +339,3 @@ TORRENT_TEST(http_pw_peer) { test_proxy(settings_pack::http_pw, dont_proxy_peers | expect_peer_connection); } - -#if TORRENT_USE_I2P -TORRENT_TEST(i2p) -{ - test_proxy(settings_pack::i2p_proxy, {}); -} -#endif diff --git a/3rd/libtorrent-rasterbar/test/test_read_resume.cpp b/3rd/libtorrent-rasterbar/test/test_read_resume.cpp index 46ec2f82..a11f41a4 100644 --- a/3rd/libtorrent-rasterbar/test/test_read_resume.cpp +++ b/3rd/libtorrent-rasterbar/test/test_read_resume.cpp @@ -66,6 +66,7 @@ TORRENT_TEST(read_resume) rd["max_connections"] = 1345; rd["max_uploads"] = 1346; rd["seed_mode"] = 0; + rd["i2p"] = 0; rd["super_seeding"] = 0; rd["added_time"] = 1347; rd["completed_time"] = 1348; @@ -100,6 +101,7 @@ TORRENT_TEST(read_resume) | torrent_flags::super_seeding | torrent_flags::auto_managed | torrent_flags::paused + | torrent_flags::i2p_torrent | torrent_flags::sequential_download; TEST_CHECK(!(atp.flags & flags_mask)); @@ -238,12 +240,40 @@ TORRENT_TEST(read_resume_torrent) namespace { -void test_roundtrip(add_torrent_params const& input) +void test_roundtrip(add_torrent_params input) { + // in order to accept that certain bitfields round up to even 8 (bytes) + // we round up the input bitfields + input.have_pieces.resize(input.have_pieces.num_bytes() * 8); + input.verified_pieces.resize(input.verified_pieces.num_bytes() * 8); + for (auto& b: input.unfinished_pieces) + b.second.resize(b.second.num_bytes() * 8); + for (auto& b: input.merkle_tree_mask) + b.resize((b.size() + 7) / 8 * 8); + for (auto& b: input.verified_leaf_hashes) + b.resize((b.size() + 7) / 8 * 8); + auto b = write_resume_data_buf(input); error_code ec; - auto output = read_resume_data(b, ec); - TEST_CHECK(write_resume_data_buf(output) == b); + auto const output = read_resume_data(b, ec); + + TEST_CHECK(input.verified_leaf_hashes == output.verified_leaf_hashes); + TEST_CHECK(input.merkle_tree_mask == output.merkle_tree_mask); + TEST_CHECK(input.file_priorities == output.file_priorities); + TEST_CHECK(input.save_path == output.save_path); + TEST_CHECK(input.name == output.name); + TEST_CHECK(input.trackers == output.trackers); + TEST_CHECK(input.tracker_tiers == output.tracker_tiers); + TEST_CHECK(input.info_hashes == output.info_hashes); + TEST_CHECK(input.url_seeds == output.url_seeds); + TEST_CHECK(input.unfinished_pieces == output.unfinished_pieces); + TEST_CHECK(input.verified_pieces == output.verified_pieces); + TEST_CHECK(input.piece_priorities == output.piece_priorities); + TEST_CHECK(input.merkle_trees == output.merkle_trees); + TEST_CHECK(input.renamed_files == output.renamed_files); + + auto const compare = write_resume_data_buf(output); + TEST_CHECK(compare == b); } template @@ -260,10 +290,12 @@ lt::typed_bitfield bits() lt::bitfield bits() { lt::bitfield b; - b.resize(19); + b.resize(190); b.set_bit(2); b.set_bit(6); b.set_bit(12); + b.set_bit(100); + b.set_bit(103); return b; } @@ -349,6 +381,9 @@ TORRENT_TEST(round_trip_flags) torrent_flags::disable_dht, torrent_flags::disable_lsd, torrent_flags::disable_pex, +#if TORRENT_USE_I2P + torrent_flags::i2p_torrent, +#endif }; for (auto const& f : flags) @@ -392,7 +427,93 @@ TORRENT_TEST(round_trip_merkle_tree_mask) TORRENT_TEST(round_trip_verified_leaf_hashes) { add_torrent_params atp; + atp.merkle_trees = aux::vector, file_index_t>{ + {sha256_hash{"01010101010101010101010101010101"}}, + {sha256_hash{"12121212121212121212121212121212"}}}; + atp.verified_leaf_hashes = aux::vector, file_index_t>{ {true, true, false, false}, {false, true, false, true}}; test_roundtrip(atp); } + +TORRENT_TEST(invalid_resume_version) +{ + entry ret; + ret["file-format"] = "libtorrent resume file"; + ret["file-version"] = 0; + ret["info-hash"] = " "; + std::vector resume_data; + bencode(std::back_inserter(resume_data), ret); + TEST_THROW(read_resume_data(resume_data)); + + ret["file-version"] = 3; + resume_data.clear(); + bencode(std::back_inserter(resume_data), ret); + TEST_THROW(read_resume_data(resume_data)); + + ret["file-version"] = 42; + resume_data.clear(); + bencode(std::back_inserter(resume_data), ret); + TEST_THROW(read_resume_data(resume_data)); +} + +TORRENT_TEST(v2_pieces_field) +{ + entry ret; + ret["file-format"] = "libtorrent resume file"; + ret["file-version"] = 2; + ret["info-hash"] = " "; + ret["pieces"] = std::string("\x05\xc0", 2); + ret["verified"] = std::string("\xc6\x80", 2); + std::vector resume_data; + bencode(std::back_inserter(resume_data), ret); + add_torrent_params const atp = read_resume_data(resume_data); + + TEST_EQUAL(atp.have_pieces.get_bit(0_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(1_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(2_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(3_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(4_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(5_piece), true); + TEST_EQUAL(atp.have_pieces.get_bit(6_piece), false); + TEST_EQUAL(atp.have_pieces.get_bit(7_piece), true); + TEST_EQUAL(atp.have_pieces.get_bit(8_piece), true); + TEST_EQUAL(atp.have_pieces.get_bit(9_piece), true); + + TEST_EQUAL(atp.verified_pieces.get_bit(0_piece), true); + TEST_EQUAL(atp.verified_pieces.get_bit(1_piece), true); + TEST_EQUAL(atp.verified_pieces.get_bit(2_piece), false); + TEST_EQUAL(atp.verified_pieces.get_bit(3_piece), false); + TEST_EQUAL(atp.verified_pieces.get_bit(4_piece), false); + TEST_EQUAL(atp.verified_pieces.get_bit(5_piece), true); + TEST_EQUAL(atp.verified_pieces.get_bit(6_piece), true); + TEST_EQUAL(atp.verified_pieces.get_bit(7_piece), false); + TEST_EQUAL(atp.verified_pieces.get_bit(8_piece), true); + TEST_EQUAL(atp.verified_pieces.get_bit(9_piece), false); +} + +TORRENT_TEST(v2_trees_fields) +{ + entry ret; + ret["file-format"] = "libtorrent resume file"; + ret["file-version"] = 2; + ret["info-hash"] = " "; + auto& tree = ret["trees"].list(); + + tree.emplace_back(entry::dictionary_t); + auto& file = tree.back().dict(); + + file["hashes"] = std::string(); + file["mask"] = "\x1a\xb8"; + file["verified"] = "\xe5\x78"; + + std::vector resume_data; + bencode(std::back_inserter(resume_data), ret); + add_torrent_params const atp = read_resume_data(resume_data); + + TEST_CHECK((atp.merkle_tree_mask.at(0) == std::vector + {false, false, false, true, true, false, true, false, true, false, true, true, true, false, false, false})); + + TEST_CHECK((atp.verified_leaf_hashes.at(0) == std::vector + {true, true, true, false, false, true, false, true, false, true, true, true, true, false, false, false})); +} diff --git a/3rd/libtorrent-rasterbar/test/test_remap_files.cpp b/3rd/libtorrent-rasterbar/test/test_remap_files.cpp index 06915ba9..d7faea36 100644 --- a/3rd/libtorrent-rasterbar/test/test_remap_files.cpp +++ b/3rd/libtorrent-rasterbar/test/test_remap_files.cpp @@ -120,12 +120,6 @@ void test_remap_files(storage_mode_t storage_mode = storage_mode_sparse) tor1.add_piece(i, std::move(piece)); } - // read pieces - for (auto const i : fs.piece_range()) - { - tor1.read_piece(i); - } - // wait for all alerts to come back and verify the data against the expected // piece data aux::vector pieces(std::size_t(fs.num_pieces()), false); @@ -170,6 +164,7 @@ void test_remap_files(storage_mode_t storage_mode = storage_mode_sparse) auto const idx = pf->piece_index; TEST_CHECK(passed[idx] == false); passed[idx] = true; + tor1.read_piece(idx); } } } diff --git a/3rd/libtorrent-rasterbar/test/test_remove_torrent.cpp b/3rd/libtorrent-rasterbar/test/test_remove_torrent.cpp index 472cc8ef..7d23876c 100644 --- a/3rd/libtorrent-rasterbar/test/test_remove_torrent.cpp +++ b/3rd/libtorrent-rasterbar/test/test_remove_torrent.cpp @@ -59,7 +59,8 @@ namespace { enum test_case { complete_download, partial_download, - mid_download + mid_download, + double_remove, }; void test_remove_torrent(remove_flags_t const remove_options @@ -152,6 +153,12 @@ void test_remove_torrent(remove_flags_t const remove_options ses2.remove_torrent(tor2, remove_options); ses1.remove_torrent(tor1, remove_options); + if (test == double_remove) + { + ses2.remove_torrent(tor2, remove_options); + ses1.remove_torrent(tor1, remove_options); + } + std::cerr << "removed" << std::endl; for (int i = 0; tor2.is_valid() || tor1.is_valid(); ++i) @@ -221,4 +228,12 @@ TORRENT_TEST(remove_torrent_and_files_mid_download) test_remove_torrent(session::delete_files, mid_download); } +TORRENT_TEST(remove_torrent_twice) +{ + test_remove_torrent({}, double_remove); +} +TORRENT_TEST(remove_torrent_and_files_twice) +{ + test_remove_torrent(session::delete_files, double_remove); +} diff --git a/3rd/libtorrent-rasterbar/test/test_resume.cpp b/3rd/libtorrent-rasterbar/test/test_resume.cpp index 29617b6e..db41725d 100644 --- a/3rd/libtorrent-rasterbar/test/test_resume.cpp +++ b/3rd/libtorrent-rasterbar/test/test_resume.cpp @@ -50,6 +50,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "setup_transfer.hpp" #include "test_utils.hpp" +#include + #include "test.hpp" #include "test_utils.hpp" #include "settings.hpp" @@ -73,7 +75,8 @@ torrent_flags_t const flags_mask | torrent_flags::super_seeding | torrent_flags::share_mode | torrent_flags::upload_mode - | torrent_flags::apply_ip_filter; + | torrent_flags::apply_ip_filter + | torrent_flags::i2p_torrent; std::vector generate_resume_data(torrent_info* ti , char const* file_priorities = "") @@ -95,11 +98,12 @@ std::vector generate_resume_data(torrent_info* ti rd["max_connections"] = 1345; rd["max_uploads"] = 1346; rd["seed_mode"] = 0; + rd["i2p"] = 0; rd["super_seeding"] = 0; rd["added_time"] = 1347; rd["completed_time"] = 1348; - rd["last_download"] = 2; - rd["last_upload"] = 3; + rd["last_download"] = time(nullptr) - 1350; + rd["last_upload"] = time(nullptr) - 1351; rd["finished_time"] = 1352; rd["last_seen_complete"] = 1353; if (file_priorities && file_priorities[0]) @@ -207,19 +211,20 @@ void default_tests(torrent_status const& s, lt::time_point const time_now) TEST_CHECK(s.active_time >= 1339); TEST_CHECK(s.active_time < 1339 + 10); - auto const now = duration_cast(time_now.time_since_epoch()).count(); - TEST_CHECK(s.time_since_download >= now - 2); - TEST_CHECK(s.time_since_upload >= now - 3); + std::cout << "time since download: " << s.time_since_download << std::endl; + TEST_CHECK(s.time_since_download >= 1350 - 3); + TEST_CHECK(s.time_since_download <= 1350 + 2); - TEST_CHECK(s.time_since_download < now - 2 + 10); - TEST_CHECK(s.time_since_upload < now - 3 + 10); + std::cout << "time since upload: " << s.time_since_upload << std::endl; + TEST_CHECK(s.time_since_upload >= 1351 - 3); + TEST_CHECK(s.time_since_upload <= 1351 + 2); TEST_CHECK(s.finished_time < 1352 + 2); TEST_CHECK(s.finished_time >= 1352); #endif using lt::seconds; - TEST_CHECK(s.finished_duration< seconds(1352 + 2)); + TEST_CHECK(s.finished_duration < seconds(1352 + 2)); TEST_CHECK(s.seeding_duration < seconds(1340 + 2)); TEST_CHECK(s.active_duration >= seconds(1339)); TEST_CHECK(s.active_duration < seconds(1339 + 10)); @@ -229,6 +234,16 @@ void default_tests(torrent_status const& s, lt::time_point const time_now) TEST_CHECK(s.completed_time < 1348 + 2); TEST_CHECK(s.completed_time >= 1348); + auto const now = lt::clock_type::now(); + std::cout << "now: " << now.time_since_epoch().count() << std::endl; + std::cout << "last_download: " << s.last_download.time_since_epoch().count() << std::endl; + TEST_CHECK(s.last_download <= now - lt::seconds(1350 - 3)); + TEST_CHECK(s.last_download >= now - lt::seconds(1350 + 2)); + + std::cout << "last_upload: " << s.last_upload.time_since_epoch().count() << std::endl; + TEST_CHECK(s.last_upload <= now - lt::seconds(1351 - 3)); + TEST_CHECK(s.last_upload >= now - lt::seconds(1351 + 2)); + TEST_EQUAL(s.last_seen_complete, 1353); } diff --git a/3rd/libtorrent-rasterbar/test/test_settings_pack.cpp b/3rd/libtorrent-rasterbar/test/test_settings_pack.cpp index 794cb997..36e2c749 100644 --- a/3rd/libtorrent-rasterbar/test/test_settings_pack.cpp +++ b/3rd/libtorrent-rasterbar/test/test_settings_pack.cpp @@ -194,7 +194,7 @@ TORRENT_TEST(clear_single_string) sp.clear(settings_pack::user_agent); // when cleared, we'll get the default value - TEST_EQUAL(sp.get_str(settings_pack::user_agent), "libtorrent/2.0.8.0"); + TEST_EQUAL(sp.get_str(settings_pack::user_agent), "libtorrent/2.0.9.0"); } TORRENT_TEST(duplicates) diff --git a/3rd/libtorrent-rasterbar/test/test_ssl.cpp b/3rd/libtorrent-rasterbar/test/test_ssl.cpp index 5c7df171..cc22946b 100644 --- a/3rd/libtorrent-rasterbar/test/test_ssl.cpp +++ b/3rd/libtorrent-rasterbar/test/test_ssl.cpp @@ -58,6 +58,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#ifdef TORRENT_UTP_LOG_ENABLE +#include "libtorrent/aux_/utp_stream.hpp" +#endif + using namespace std::placeholders; using namespace lt; using std::ignore; @@ -134,6 +138,10 @@ void test_ssl(int const test_idx, bool const use_utp) session_proxy p1; session_proxy p2; +#ifdef TORRENT_UTP_LOG_ENABLE + lt::aux::set_utp_stream_logging(use_utp); +#endif + test_config_t const& test = test_config[test_idx]; std::printf("\n%s TEST: %s Protocol: %s\n\n", time_now_string().c_str() diff --git a/3rd/libtorrent-rasterbar/test/test_string.cpp b/3rd/libtorrent-rasterbar/test/test_string.cpp index b0c5af81..1e8e50f0 100644 --- a/3rd/libtorrent-rasterbar/test/test_string.cpp +++ b/3rd/libtorrent-rasterbar/test/test_string.cpp @@ -211,6 +211,32 @@ TORRENT_TEST(to_string) TEST_CHECK(to_string(-999999999999999999).data() == std::string("-999999999999999999")); } +namespace { + +template +std::vector to_vec(char const (&str)[N]) +{ + return std::vector(&str[0], &str[N - 1]); +} + +std::string to_str(std::vector const& v) +{ + return std::string(v.begin(), v.end()); +} + +// convert the standard base64 alphabet to the i2p aphabet +std::string transcode_alphabet(std::string in) +{ + std::string ret; + std::transform(in.begin(), in.end(), std::back_inserter(ret), [](char const c) { + if (c == '+') return '-'; + if (c == '/') return '~'; + return c; + }); + return ret; +} +} + TORRENT_TEST(base64) { // base64 test vectors from http://www.faqs.org/rfcs/rfc4648.html @@ -221,6 +247,20 @@ TORRENT_TEST(base64) TEST_CHECK(base64encode("foob") == "Zm9vYg=="); TEST_CHECK(base64encode("fooba") == "Zm9vYmE="); TEST_CHECK(base64encode("foobar") == "Zm9vYmFy"); +#if TORRENT_USE_I2P + TEST_CHECK(base64decode_i2p("") == to_vec("")); + TEST_CHECK(base64decode_i2p("Zg==") == to_vec("f")); + TEST_CHECK(base64decode_i2p("Zm8=") == to_vec("fo")); + TEST_CHECK(base64decode_i2p("Zm9v") == to_vec("foo")); + TEST_CHECK(base64decode_i2p("Zm9vYg==") == to_vec("foob")); + TEST_CHECK(base64decode_i2p("Zm9vYmE=") == to_vec("fooba")); + TEST_CHECK(base64decode_i2p("Zm9vYmFy") == to_vec("foobar")); + + std::vector test; + for (int i = 0; i < 255; ++i) + test.push_back(char(i)); + TEST_CHECK(base64decode_i2p(transcode_alphabet(base64encode(to_str(test)))) == test); +#endif } TORRENT_TEST(base32) @@ -228,24 +268,20 @@ TORRENT_TEST(base32) // base32 test vectors from http://www.faqs.org/rfcs/rfc4648.html #if TORRENT_USE_I2P - TEST_CHECK(base32encode("") == ""); - TEST_CHECK(base32encode("f") == "MY======"); - TEST_CHECK(base32encode("fo") == "MZXQ===="); - TEST_CHECK(base32encode("foo") == "MZXW6==="); - TEST_CHECK(base32encode("foob") == "MZXW6YQ="); - TEST_CHECK(base32encode("fooba") == "MZXW6YTB"); - TEST_CHECK(base32encode("foobar") == "MZXW6YTBOI======"); - - // base32 for i2p - TEST_CHECK(base32encode("fo", string::no_padding) == "MZXQ"); - TEST_CHECK(base32encode("foob", string::i2p) == "mzxw6yq"); - TEST_CHECK(base32encode("foobar", string::lowercase) == "mzxw6ytboi======"); + // i2p uses lower case and no padding + TEST_CHECK(base32encode_i2p(""_sv) == ""); + TEST_CHECK(base32encode_i2p("f"_sv) == "my"); + TEST_CHECK(base32encode_i2p("fo"_sv) == "mzxq"); + TEST_CHECK(base32encode_i2p("foo"_sv) == "mzxw6"); + TEST_CHECK(base32encode_i2p("foob"_sv) == "mzxw6yq"); + TEST_CHECK(base32encode_i2p("fooba"_sv) == "mzxw6ytb"); + TEST_CHECK(base32encode_i2p("foobar"_sv) == "mzxw6ytboi"); std::string test; for (int i = 0; i < 255; ++i) test += char(i); - TEST_CHECK(base32decode(base32encode(test)) == test); + TEST_CHECK(base32decode(base32encode_i2p(test)) == test); #endif // TORRENT_USE_I2P TEST_CHECK(base32decode("") == ""); diff --git a/3rd/libtorrent-rasterbar/test/test_time.cpp b/3rd/libtorrent-rasterbar/test/test_time.cpp index ee5f38ff..c119014f 100644 --- a/3rd/libtorrent-rasterbar/test/test_time.cpp +++ b/3rd/libtorrent-rasterbar/test/test_time.cpp @@ -34,11 +34,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "libtorrent/time.hpp" +#include "libtorrent/aux_/time.hpp" #include #include #include #include +#include using namespace lt; @@ -103,3 +105,43 @@ TORRENT_TEST(time) t4.join(); } +TORRENT_TEST(test_time_conversion) +{ + int success = 0; + const int test_count = 10; + + for (int i = 0; i < test_count; ++i) + { + auto now = aux::time_now32() + seconds32(rand() % 1000); + auto ctime = aux::to_time_t(now); + auto converted = aux::from_time_t(ctime); + if (now == converted) + ++success; + else + std::cout << "now: " << now.time_since_epoch().count() << " converted: " << converted.time_since_epoch().count() << '\n'; + } + + // conversion depends on wall clock and may be flaky + TEST_CHECK(success >= test_count - 1); +} + +TORRENT_TEST(test_time_conversion_with_offset) +{ + int success = 0; + const int test_count = 10; + + for (int i = 0; i < test_count; ++i) + { + auto now = aux::time_now32() + seconds32(rand() % 1000); + auto ctime = aux::to_time_t(now); + // offset by 100 seconds + auto converted = aux::from_time_t(ctime + 100); + if (now + seconds32(100) == converted) + ++success; + else + std::cout << "now: " << now.time_since_epoch().count() << " converted: " << converted.time_since_epoch().count() << '\n'; + } + + // conversion depends on wall clock and may be flaky + TEST_CHECK(success >= test_count - 1); +} diff --git a/3rd/libtorrent-rasterbar/test/test_torrent_info.cpp b/3rd/libtorrent-rasterbar/test/test_torrent_info.cpp index 12ef17e2..eba46eb5 100644 --- a/3rd/libtorrent-rasterbar/test/test_torrent_info.cpp +++ b/3rd/libtorrent-rasterbar/test/test_torrent_info.cpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "test.hpp" #include "setup_transfer.hpp" // for load_file #include "test_utils.hpp" +#include "settings.hpp" #include "libtorrent/file_storage.hpp" #include "libtorrent/load_torrent.hpp" #include "libtorrent/aux_/path.hpp" @@ -434,6 +435,8 @@ test_failing_torrent_t test_error_torrents[] = { "v2_non_multiple_piece_layer.torrent", errors::torrent_invalid_piece_layer}, { "v2_piece_layer_invalid_file_hash.torrent", errors::torrent_invalid_piece_layer}, { "v2_invalid_piece_layer.torrent", errors::torrent_invalid_piece_layer}, + { "v2_invalid_piece_layer_root.torrent", errors::torrent_invalid_piece_layer}, + { "v2_unknown_piece_layer_entry.torrent", errors::torrent_invalid_piece_layer}, { "v2_invalid_piece_layer_size.torrent", errors::torrent_invalid_piece_layer}, { "v2_bad_file_alignment.torrent", errors::torrent_inconsistent_files}, { "v2_unordered_files.torrent", errors::invalid_bencoding}, @@ -1090,12 +1093,19 @@ TORRENT_TEST(parse_invalid_torrents) auto ti = std::make_shared(filename, ec); std::printf("E: \"%s\"\nexpected: \"%s\"\n", ec.message().c_str() , e.error.message().c_str()); - TEST_EQUAL(ec.message(), e.error.message()); - TEST_EQUAL(ti->is_valid(), false); + // Some checks only happen in the load_torrent_*() functions, not in the + // torrent_info constructor. For these, it's OK for ec to not report an + // error + if (e.error != errors::torrent_invalid_piece_layer || ec) + { + TEST_EQUAL(ec.message(), e.error.message()); + TEST_EQUAL(ti->is_valid(), false); + } try { add_torrent_params atp = load_torrent_file(filename); + TORRENT_ASSERT(!e.error); } catch (system_error const& err) { @@ -1363,7 +1373,7 @@ TORRENT_TEST(torrent_info_with_hashes_roundtrip) atp.ti = ti; atp.save_path = "."; - session ses; + session ses(settings()); torrent_handle h = ses.add_torrent(atp); TEST_CHECK(ti->v2()); @@ -1459,7 +1469,7 @@ TORRENT_TEST(write_torrent_file_session_roundtrip) atp.ti = ti; atp.save_path = "."; - session ses; + session ses(settings()); torrent_handle h = ses.add_torrent(atp); h.save_resume_data(torrent_handle::save_info_dict); diff --git a/3rd/libtorrent-rasterbar/test/test_torrents/v2_invalid_piece_layer_root.torrent b/3rd/libtorrent-rasterbar/test/test_torrents/v2_invalid_piece_layer_root.torrent new file mode 100644 index 00000000..91d76cc4 --- /dev/null +++ b/3rd/libtorrent-rasterbar/test/test_torrents/v2_invalid_piece_layer_root.torrent @@ -0,0 +1,17 @@ +d8:announce27:http://example.com/announce4:infod9:file treed7:test1MBd0:d6:lengthi1048576e11:pieces root32:Q^©D¸tMí.ŽÆ¨E RâKPwóÿ½eee12:meta versioni2e4:name7:test1MB12:piece lengthi65536ee12:piece layersd32:Q^©D¸tMí.ŽÆ¨E RâKPwóÿ½512:`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ë6òB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòBee diff --git a/3rd/libtorrent-rasterbar/test/test_torrents/v2_unknown_piece_layer_entry.torrent b/3rd/libtorrent-rasterbar/test/test_torrents/v2_unknown_piece_layer_entry.torrent new file mode 100644 index 00000000..347a719e --- /dev/null +++ b/3rd/libtorrent-rasterbar/test/test_torrents/v2_unknown_piece_layer_entry.torrent @@ -0,0 +1,33 @@ +d8:announce27:http://example.com/announce4:infod9:file treed7:test1MBd0:d6:lengthi1048576e11:pieces root32:Q^©D¸tMí.ŽÆ¨E RâKPwóÿ½eee12:meta versioni2e4:name7:test1MB12:piece lengthi65536ee12:piece layersd32:Q^©D¸tMí.ŽÆ¨E RâKPwóÿ½512:`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB32:Q^©E¸tMí.ŽÆ¨E RâKPwóÿ½512:`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòB`ªéÇ´(ø~è‚)á +ßÍ{" ÝŠ’»$…ëzòBee diff --git a/3rd/libtorrent-rasterbar/test/test_tracker.cpp b/3rd/libtorrent-rasterbar/test/test_tracker.cpp index 9b20585a..f46f011e 100644 --- a/3rd/libtorrent-rasterbar/test/test_tracker.cpp +++ b/3rd/libtorrent-rasterbar/test/test_tracker.cpp @@ -168,7 +168,7 @@ TORRENT_TEST(parse_i2p_peers) , ec, tracker_request::i2p, sha1_hash()); TEST_EQUAL(ec, error_code()); - TEST_EQUAL(resp.peers.size(), 11); + TEST_EQUAL(resp.i2p_peers.size(), 11); if (resp.peers.size() == 11) { diff --git a/3rd/libtorrent-rasterbar/test/test_utils.cpp b/3rd/libtorrent-rasterbar/test/test_utils.cpp index dd7feeb2..5e7e6da5 100644 --- a/3rd/libtorrent-rasterbar/test/test_utils.cpp +++ b/3rd/libtorrent-rasterbar/test/test_utils.cpp @@ -94,7 +94,7 @@ aux::vector build_tree(int const size) return full_tree; } -#ifdef _WIN32 +#if defined _WIN32 && !defined TORRENT_MINGW int EXPORT truncate(char const* file, std::int64_t size) { int fd = ::_open(file, _O_WRONLY); diff --git a/3rd/libtorrent-rasterbar/test/test_utils.hpp b/3rd/libtorrent-rasterbar/test/test_utils.hpp index d9bae4a1..19d08ba1 100644 --- a/3rd/libtorrent-rasterbar/test/test_utils.hpp +++ b/3rd/libtorrent-rasterbar/test/test_utils.hpp @@ -66,7 +66,7 @@ EXPORT std::vector serialize(lt::torrent_info const& ti); EXPORT lt::aux::vector build_tree(int const size); -#ifdef _WIN32 +#if defined _WIN32 && !defined TORRENT_MINGW int EXPORT truncate(char const* file, std::int64_t size); #endif diff --git a/3rd/qtsingleapplication/src/qtlocalpeer.cpp b/3rd/qtsingleapplication/src/qtlocalpeer.cpp index 9815ccb0..512d19f8 100644 --- a/3rd/qtsingleapplication/src/qtlocalpeer.cpp +++ b/3rd/qtsingleapplication/src/qtlocalpeer.cpp @@ -49,7 +49,7 @@ #include #include typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*); -static PProcessIdToSessionId pProcessIdToSessionId = Q_NULLPTR; +static PProcessIdToSessionId pProcessIdToSessionId = nullptr; #endif #if defined(Q_OS_UNIX) #include diff --git a/3rd/qtsingleapplication/src/qtlocalpeer.h b/3rd/qtsingleapplication/src/qtlocalpeer.h index 56db44a6..564db7c3 100644 --- a/3rd/qtsingleapplication/src/qtlocalpeer.h +++ b/3rd/qtsingleapplication/src/qtlocalpeer.h @@ -52,7 +52,7 @@ class QtLocalPeer : public QObject Q_OBJECT public: - QtLocalPeer(QObject *parent = Q_NULLPTR, const QString &appId = QString()); + QtLocalPeer(QObject *parent = nullptr, const QString &appId = {}); bool isClient(); bool sendMessage(const QString &message, int timeout); QString applicationId() const diff --git a/3rd/qtsingleapplication/src/qtsingleapplication.h b/3rd/qtsingleapplication/src/qtsingleapplication.h index 68fbb8c0..912cd181 100644 --- a/3rd/qtsingleapplication/src/qtsingleapplication.h +++ b/3rd/qtsingleapplication/src/qtsingleapplication.h @@ -43,6 +43,8 @@ #include +using namespace Qt::Literals::StringLiterals; + class QtLocalPeer; #if defined(Q_OS_WIN) @@ -97,7 +99,7 @@ public Q_SLOTS: private: - void sysInit(const QString &appId = QString()); + void sysInit(const QString &appId = {}); QtLocalPeer *peer; QWidget *actWin; }; diff --git a/3rd/yt-dlp/bin/yt-dlp b/3rd/yt-dlp/bin/yt-dlp index 10feb622..a338f4bb 100644 Binary files a/3rd/yt-dlp/bin/yt-dlp and b/3rd/yt-dlp/bin/yt-dlp differ diff --git a/3rd/yt-dlp/bin/yt-dlp.exe b/3rd/yt-dlp/bin/yt-dlp.exe index 74c4876b..c9cbb09d 100644 Binary files a/3rd/yt-dlp/bin/yt-dlp.exe and b/3rd/yt-dlp/bin/yt-dlp.exe differ diff --git a/3rd/yt-dlp/version b/3rd/yt-dlp/version index 7c1eece5..c0022235 100644 --- a/3rd/yt-dlp/version +++ b/3rd/yt-dlp/version @@ -1 +1 @@ -2023.03.04 +2023.11.16 diff --git a/README.md b/README.md index 60f7aa89..506149df 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ [![Chrome Web Store](https://img.shields.io/chrome-web-store/users/modofbhnhlagjmejdbalnijgncppjeio?label=users&logo=google)](https://chrome.google.com/webstore/detail/down-right-now/modofbhnhlagjmejdbalnijgncppjeio "Google Chrome Add-on") [![Mozilla Add-on](https://img.shields.io/amo/users/down-right-now?label=users&logo=mozilla)](https://addons.mozilla.org/firefox/addon/down-right-now/ "Mozilla Firefox Add-on") ![GitHub All Releases](https://img.shields.io/github/downloads/setvisible/DownZemAll/total) +[![Chocolatey package](https://img.shields.io/chocolatey/dt/downzemall?color=blue&label=chocolatey%20package)](https://community.chocolatey.org/packages/downzemall) [![Twitter Follow](https://img.shields.io/twitter/follow/downzemall?label=Follow)](https://twitter.com/downzemall) @@ -56,6 +57,10 @@ Go to [Download](https://setvisible.github.io/DownZemAll/category/download.html) Rem: *Native-Client* is an alternative to *DownRightNow*. Click [here](NativeClient.md "NativeClient.md") for more information. +On Windows, you can also use the [Chocolatey package](https://community.chocolatey.org/packages/downzemall) to handle the installation/updates: +```powershell +choco install downzemall +``` ## Usage diff --git a/cmake/Modules/FindOpenSSLPreferablyFromQt6.cmake b/cmake/Modules/FindOpenSSLPreferablyFromQt6.cmake index 034add0c..65de4be2 100644 --- a/cmake/Modules/FindOpenSSLPreferablyFromQt6.cmake +++ b/cmake/Modules/FindOpenSSLPreferablyFromQt6.cmake @@ -10,19 +10,19 @@ if(NOT OpenSSL_ROOT_DIR) if(MSVC OR MSYS OR MINGW) # for detecting Windows compilers # Warning: Qt6_DIR is not always the same: - # On remote 'Github Actions' runner : Qt6_DIR: D:\a\project\my-qt\Qt\6.3.1\mingw_64 - # On local it points to : Qt6_DIR: D:\a\project\my-qt\6.3.1\mingw_64\lib\cmake\Qt6 + # On remote 'Github Actions' runner : Qt6_DIR: D:\a\project\my-qt\Qt\X.Y.Z\mingw_64 + # On local it points to : Qt6_DIR: D:\a\project\my-qt\X.Y.Z\mingw_64\lib\cmake\Qt6 if(Qt6Core_DIR) - # Qt6Core_DIR: D:\a\project\my-qt\6.3.1\mingw_64\lib\cmake\Qt6Core + # Qt6Core_DIR: D:\a\project\my-qt\X.Y.Z\mingw_64\lib\cmake\Qt6Core # TODO use cmake_path? get_filename_component(Qt6_OPENSSL_DIR ${Qt6Core_DIR} DIRECTORY) get_filename_component(Qt6_OPENSSL_DIR ${Qt6_OPENSSL_DIR} DIRECTORY) # like "cd ..". Move to parent directory. get_filename_component(Qt6_OPENSSL_DIR ${Qt6_OPENSSL_DIR} DIRECTORY) get_filename_component(Qt6_OPENSSL_DIR ${Qt6_OPENSSL_DIR} DIRECTORY) get_filename_component(Qt6_OPENSSL_DIR ${Qt6_OPENSSL_DIR} DIRECTORY) - set(OpenSSL_ROOT_DIR "${Qt6_OPENSSL_DIR}/Tools/OpenSSL/Win_x64/") + set(OpenSSL_ROOT_DIR "${Qt6_OPENSSL_DIR}/Tools/OpenSSLv3/Win_x64/") endif() @@ -39,16 +39,26 @@ if(EXISTS "${OpenSSL_ROOT_DIR}/include/openssl/ssl.h") set(OPENSSL_CRYPTO_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libcrypto.lib" CACHE PATH "Location of the OpenSSL Crypto Lib") set(OPENSSL_SSL_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libssl.lib" CACHE PATH "Location of the OpenSSL SSL Lib") set(OPENSSL_INCLUDE_DIRS "${OpenSSL_ROOT_DIR}/include" CACHE PATH "Location of the OpenSSL include files") - set(OPENSSL_CRYPTO_BIN "${OpenSSL_ROOT_DIR}/bin/libcrypto-1_1-x64.dll" CACHE PATH "Location of the OpenSSL Crypto DLL") - set(OPENSSL_SSL_BIN "${OpenSSL_ROOT_DIR}/bin/libssl-1_1-x64.dll" CACHE PATH "Location of the OpenSSL SSL DLL") + set(OPENSSL_CRYPTO_BIN "${OpenSSL_ROOT_DIR}/bin/libcrypto-3-x64.dll" CACHE PATH "Location of the OpenSSL Crypto DLL") + set(OPENSSL_SSL_BIN "${OpenSSL_ROOT_DIR}/bin/libssl-3-x64.dll" CACHE PATH "Location of the OpenSSL SSL DLL") else() # MacOS or Unix Compilers - set(OPENSSL_CRYPTO_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libcrypto.so" CACHE PATH "Location of the OpenSSL Crypto Lib") - set(OPENSSL_SSL_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libssl.so" CACHE PATH "Location of the OpenSSL SSL Lib") + # To use preinstalled libssl-dev in Ubuntu: + # OpenSSL_ROOT_DIR = '/usr' + set(OPENSSL_CRYPTO_LIBRARY "${OpenSSL_ROOT_DIR}/lib/x86_64-linux-gnu/libcrypto.so" CACHE PATH "Location of the OpenSSL Crypto Lib") + set(OPENSSL_SSL_LIBRARY "${OpenSSL_ROOT_DIR}/lib/x86_64-linux-gnu/libssl.so" CACHE PATH "Location of the OpenSSL SSL Lib") set(OPENSSL_INCLUDE_DIRS "${OpenSSL_ROOT_DIR}/include" CACHE PATH "Location of the OpenSSL include files") - set(OPENSSL_CRYPTO_BIN "${OpenSSL_ROOT_DIR}/lib/libcrypto.so.1.1" CACHE PATH "Location of the OpenSSL Crypto DLL") - set(OPENSSL_SSL_BIN "${OpenSSL_ROOT_DIR}/lib/libssl.so.1.1" CACHE PATH "Location of the OpenSSL SSL DLL") + set(OPENSSL_CRYPTO_BIN "${OpenSSL_ROOT_DIR}/lib/x86_64-linux-gnu/libcrypto.so.3" CACHE PATH "Location of the OpenSSL Crypto DLL") + set(OPENSSL_SSL_BIN "${OpenSSL_ROOT_DIR}/lib/x86_64-linux-gnu/libssl.so.3" CACHE PATH "Location of the OpenSSL SSL DLL") + + # ...or to build it from Qt: + # OpenSSL_ROOT_DIR = '~/work/DownZemAll/qt/Qt/Tools/OpenSSLv3/src' + # set(OPENSSL_CRYPTO_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libcrypto.so" CACHE PATH "Location of the OpenSSL Crypto Lib") + # set(OPENSSL_SSL_LIBRARY "${OpenSSL_ROOT_DIR}/lib/libssl.so" CACHE PATH "Location of the OpenSSL SSL Lib") + # set(OPENSSL_INCLUDE_DIRS "${OpenSSL_ROOT_DIR}/include" CACHE PATH "Location of the OpenSSL include files") + # set(OPENSSL_CRYPTO_BIN "${OpenSSL_ROOT_DIR}/lib/libcrypto.so.3" CACHE PATH "Location of the OpenSSL Crypto DLL") + # set(OPENSSL_SSL_BIN "${OpenSSL_ROOT_DIR}/lib/libssl.so.3" CACHE PATH "Location of the OpenSSL SSL DLL") endif() diff --git a/include/Constants b/include/Constants new file mode 100644 index 00000000..ce8d2c8b --- /dev/null +++ b/include/Constants @@ -0,0 +1 @@ +#include "../src/constants.h" diff --git a/include/Globals b/include/Globals deleted file mode 100644 index 4c0c0148..00000000 --- a/include/Globals +++ /dev/null @@ -1 +0,0 @@ -#include "../src/globals.h" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b7555507..9bb7514c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,6 +106,8 @@ if(MSVC OR MSYS OR MINGW) # for detecting Windows compilers # debug # dbghelp + bcrypt # required by libtorrent-rasterbar >= 2.0.9 + version.dll # might be "C:/Windows/System32/version.dll" or "C:/Windows/SysWOW64/version.dll" crypt32 # required by openssl @@ -285,23 +287,23 @@ else() # MacOS or Unix Compilers # Rem: ${QT_SHARED_LIB_DIR}/libQt6Core.so is not a file but a namelink (symbolic link) ${QT_SHARED_LIB_DIR}/libQt6Core.so # required by libQt6Gui ${QT_SHARED_LIB_DIR}/libQt6Core.so.6 - ${QT_SHARED_LIB_DIR}/libQt6Core.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6Core.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6Gui.so # required by libQt6Widgets ${QT_SHARED_LIB_DIR}/libQt6Gui.so.6 - ${QT_SHARED_LIB_DIR}/libQt6Gui.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6Gui.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6Widgets.so ${QT_SHARED_LIB_DIR}/libQt6Widgets.so.6 - ${QT_SHARED_LIB_DIR}/libQt6Widgets.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6Widgets.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6Network.so ${QT_SHARED_LIB_DIR}/libQt6Network.so.6 - ${QT_SHARED_LIB_DIR}/libQt6Network.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6Network.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6DBus.so # required by libQt6Gui ${QT_SHARED_LIB_DIR}/libQt6DBus.so.6 - ${QT_SHARED_LIB_DIR}/libQt6DBus.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6DBus.so.6.5.3 ${QT_SHARED_LIB_DIR}/libicudata.so # required by libQt6Core ${QT_SHARED_LIB_DIR}/libicudata.so.56 @@ -337,23 +339,23 @@ else() # MacOS or Unix Compilers ${QT_SHARED_LIB_DIR}/libQt6XcbQpa.so # required by libqxcb ${QT_SHARED_LIB_DIR}/libQt6XcbQpa.so.6 - ${QT_SHARED_LIB_DIR}/libQt6XcbQpa.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6XcbQpa.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6OpenGL.so # required by libqxcb ${QT_SHARED_LIB_DIR}/libQt6OpenGL.so.6 - ${QT_SHARED_LIB_DIR}/libQt6OpenGL.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6OpenGL.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6OpenGLWidgets.so # in case? ${QT_SHARED_LIB_DIR}/libQt6OpenGLWidgets.so.6 - ${QT_SHARED_LIB_DIR}/libQt6OpenGLWidgets.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6OpenGLWidgets.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6WaylandClient.so # required by libqwayland-generic and libqwayland-egl ${QT_SHARED_LIB_DIR}/libQt6WaylandClient.so.6 - ${QT_SHARED_LIB_DIR}/libQt6WaylandClient.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6WaylandClient.so.6.5.3 ${QT_SHARED_LIB_DIR}/libQt6WaylandEglClientHwIntegration.so # required by libqwayland-egl ${QT_SHARED_LIB_DIR}/libQt6WaylandEglClientHwIntegration.so.6 - ${QT_SHARED_LIB_DIR}/libQt6WaylandEglClientHwIntegration.so.6.3.1 + ${QT_SHARED_LIB_DIR}/libQt6WaylandEglClientHwIntegration.so.6.5.3 DESTINATION ${CMAKE_INSTALL_PREFIX} ) diff --git a/src/about.h b/src/about.h index 9c967fc6..3d9202bc 100644 --- a/src/about.h +++ b/src/about.h @@ -17,7 +17,6 @@ #ifndef ABOUT_H #define ABOUT_H -#include "globals.h" #include "version.h" #include diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 00000000..39ee2130 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,259 @@ +/* - DownZemAll! - Copyright (C) 2019-present Sebastien Vavassori + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, see . + */ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#include "version.h" + +#include +#include + +const int DEFAULT_WIDTH = 1000; +const int DEFAULT_HEIGHT = 700; +const int DEFAULT_X = 100; +const int DEFAULT_Y = 100; + +const std::chrono::milliseconds TIMEOUT_TUTORIAL(250); +const std::chrono::milliseconds TIMEOUT_STATUSBAR(2000); +const std::chrono::milliseconds TIMEOUT_STATUSBAR_LONG(5000); + +const int DIALOG_WIDTH = 600; + +const int DEFAULT_TIMEOUT_SECS = 30; // ref.: QNetworkConfigurationPrivate::DefaultTimeout +const int DEFAULT_CONCURRENT_FRAGMENTS = 20; + +const int MAX_CONNECTION_SEGMENTS = 10; + +const std::chrono::milliseconds TIMEOUT_COUNT_DOWN(1000); +const std::chrono::milliseconds TIMEOUT_INFO(150); + +const int SELECTION_DISPLAY_LIMIT = 10; +const int MSEC_SPEED_DISPLAY_TIME = 2000; + +const int MSEC_AUTO_SAVE = 3000; ///< Autosave the queue every 3 seconds. + +/* + * Remark: + * Characters '<' and '>' are unlikely to be used as value for data or directory path. + * If a collision appears, the only risk is to reset the faulty parameter + * to its default value. + */ +const QLatin1StringView UNDEFINED(""); +const QLatin1StringView VALUE_TRUE(""); +const QLatin1StringView VALUE_FALSE(""); + +const QLatin1StringView SETTING_GROUP_PREFERENCE("Preference"); + +// ******************************************************** +// Inpired by: QtCreator source code +// Utils::FileNameValidatingLineEdit::validateFileName +// ******************************************************** +/* + * Naming a file like a device name will break on Windows, + * even if it is "com1.txt". + * Since we are cross-platform, we generally disallow such file names. + */ +#define WINDOWS_RESERVED_DEVICE_NAMES \ + "CON|PRN|AUX|NUL" \ + "|COM1|COM2|COM3|COM4|COM5|COM6|COM7|COM8|COM9" \ + "|LPT1|LPT2|LPT3|LPT4|LPT5|LPT6|LPT7|LPT8|LPT9" + +/* + * Validate a file base name, check for forbidden characters/strings. + */ +#define PRINTABLE_ASCII_CHARS "<>:\"|?*" +#define SLASHES "/\\" + +const char S_FORBIDDEN_CHARS_SUB_DIR[] = PRINTABLE_ASCII_CHARS; +const char S_FORBIDDEN_CHARS_NO_SUB_DIR[] = PRINTABLE_ASCII_CHARS SLASHES; + +const QString S_SUBSTITUTE_CHAR('_'); +const QLatin1StringView S_SUBSTITUTE_FILE_NAME("file"); + +/* + * This list of legal characters for filenames is limited to avoid injections + * of special or invisible characters that could be not supported by the OS. + */ +const QLatin1StringView C_LEGAL_CHARS("-+' @()[]{}°#,.&"); + +const QLatin1StringView S_KEY_REGULAR("regular"); +const QLatin1StringView S_KEY_STREAM("stream"); +const QLatin1StringView S_KEY_TORRENT("torrent"); + +const QString SYMBOL_INFINITE = QString::fromUtf8("\xE2\x88\x9E"); + +const qint64 ONE_DAY_IN_SECONDS = 24 * 60 * 60; + +const QLatin1StringView NAME("*name*"); +const QLatin1StringView EXT("*ext*"); +const QLatin1StringView URL("*url*"); +const QLatin1StringView CURL("*curl*"); +const QLatin1StringView FLATURL("*flaturl*"); +const QLatin1StringView SUBDIRS("*subdirs*"); +const QLatin1StringView FLATSUBDIRS("*flatsubdirs*"); +const QLatin1StringView QSTRING("*qstring*"); + +const int MSEC_MESSAGE_TIMEOUT = 2000; + +const int DEFAULT_ICON_SIZE = 32; +const int ICON_SIZE = 16; +const int ICON_WIDTH = 19; + +const int MAX_REDIRECTS_ALLOWED = 5; + +const int COLUMN_MINIMUM_WIDTH = 10; +const int COLUMN_DEFAULT_WIDTH = 100; +const int VERTICAL_HEADER_WIDTH = 22; +const int COLUMN_MAX_WIDTH = 1000; + +const int COLUMN_0_DEFAULT_WIDTH = 300; +const int ROW_DEFAULT_HEIGHT = 22; +//const int ROW_DEFAULT_HEIGHT = 18; + +const int MIN_PROGRESS = 0; +const int MAX_PROGRESS = 100; + +const int VERSION_MARKER = 0xff; + +const int COLUMN_ID_WIDTH = 10; +const int COLUMN_NAME_WIDTH = 200; + +const int ELIDE_CHAR_COUNT = 30; + +const int COL_0_FILE_NAME = 0; +const int COL_1_WEBSITE_DOMAIN = 1; +const int COL_2_PROGRESS_BAR = 2; +const int COL_3_PERCENT = 3; +const int COL_4_SIZE = 4; +const int COL_5_ESTIMATED_TIME = 5; +const int COL_6_SPEED = 6; +// const int COL_7_SEGMENTS = 7; /* hidden */ +// const int COL_8_MASK = 8; /* hidden */ +// const int COL_9_SAVE_PATH = 9; /* hidden */ +// const int COL_10_CHECKSUM = 10; /* hidden */ + +const int MAX_HISTORY_COUNT = 10; + +const int CHECKBOX_SIZE = 12; +const int CHECKBOX_WIDTH = 16; +const int THUMBNAIL_WIDTH = 16; + +const qsizetype MAX_PEER_LIST_COUNT = 1024; + +/*! + * Registry Keys. They must be unique + */ +// Tab General +const QLatin1StringView REGISTRY_EXISTING_FILE ("ExistingFile"); + +// Tab Interface +const QLatin1StringView REGISTRY_UI_LANGUAGE ("Language"); +const QLatin1StringView REGISTRY_UI_THEME ("Theme"); +const QLatin1StringView REGISTRY_DONT_SHOW_TUTO ("DontShowTutorial"); +const QLatin1StringView REGISTRY_SHOW_SYSTEM_TRAY ("SystemTrayIconEnabled"); +const QLatin1StringView REGISTRY_HIDE_MINIMIZED ("HideWhenMinimized"); +const QLatin1StringView REGISTRY_SHOW_BALLOON ("SystemTrayBalloonEnabled"); +const QLatin1StringView REGISTRY_MINIMIZE_ESCAPE ("MinimizeWhenEscapePressed"); +const QLatin1StringView REGISTRY_CONFIRM_REMOVAL ("ConfirmRemoval"); +const QLatin1StringView REGISTRY_CONFIRM_BATCH ("ConfirmBatchDownload"); +const QLatin1StringView REGISTRY_PROXY_TYPE ("ProxyType"); +const QLatin1StringView REGISTRY_PROXY_HOSTNAME ("ProxyHostName"); +const QLatin1StringView REGISTRY_PROXY_PORT ("ProxyPort"); +const QLatin1StringView REGISTRY_PROXY_IS_AUTH ("ProxyAuth"); +const QLatin1StringView REGISTRY_PROXY_USERNAME ("ProxyUser"); +const QLatin1StringView REGISTRY_PROXY_PASSWORD ("ProxyPwd"); +const QLatin1StringView REGISTRY_SOCKET_TYPE ("SocketType"); +const QLatin1StringView REGISTRY_SOCKET_TIMEOUT ("SocketTimeout"); +const QLatin1StringView REGISTRY_REMOTE_CREATION ("RemoteCreationTime"); +const QLatin1StringView REGISTRY_REMOTE_LAST_MOD ("RemoteLastModifiedTime"); +const QLatin1StringView REGISTRY_REMOTE_ACCESS ("RemoteAccessTime"); +const QLatin1StringView REGISTRY_REMOTE_META_MOD ("RemoteMetadataChangeTime"); +const QLatin1StringView REGISTRY_STREAM_WATCHED ("StreamMarkWatchedEnabled"); +const QLatin1StringView REGISTRY_STREAM_SUBTITLE ("StreamSubtitleEnabled"); +const QLatin1StringView REGISTRY_STREAM_THUMBNAIL ("StreamThumbnailEnabled"); +const QLatin1StringView REGISTRY_STREAM_DESCR ("StreamDescriptionEnabled"); +const QLatin1StringView REGISTRY_STREAM_METADATA ("StreamMetaDataEnabled"); +const QLatin1StringView REGISTRY_STREAM_COMMENT ("StreamCommentEnabled"); +const QLatin1StringView REGISTRY_STREAM_SHORTCUT ("StreamShortcutEnabled"); + +// Tab Network +const QLatin1StringView REGISTRY_MAX_SIMULTANEOUS ("MaxSimultaneous"); +const QLatin1StringView REGISTRY_CONCURRENT_FRAG ("ConcurrentFragments"); +const QLatin1StringView REGISTRY_CUSTOM_BATCH ("CustomBatchEnabled"); +const QLatin1StringView REGISTRY_CUSTOM_BATCH_BL ("CustomBatchButtonLabel"); +const QLatin1StringView REGISTRY_CUSTOM_BATCH_RGE ("CustomBatchRange"); +const QLatin1StringView REGISTRY_STREAM_HOST ("StreamHostEnabled"); +const QLatin1StringView REGISTRY_STREAM_HOST_LIST ("StreamHosts"); + +// Tab Privacy +const QLatin1StringView REGISTRY_REMOVE_COMPLETED ("PrivacyRemoveCompleted"); +const QLatin1StringView REGISTRY_REMOVE_CANCELED ("PrivacyRemoveCanceled"); +const QLatin1StringView REGISTRY_REMOVE_PAUSED ("PrivacyRemovePaused"); +const QLatin1StringView REGISTRY_DATABASE ("Database"); +const QLatin1StringView REGISTRY_HTTP_USER_AGENT ("HttpUserAgent"); +const QLatin1StringView REGISTRY_HTTP_REFERRER_ON ("HttpReferringPageEnabled"); +const QLatin1StringView REGISTRY_HTTP_REFERRER ("HttpReferringPage"); + +// Tab Filters +const QLatin1StringView REGISTRY_FILTER_KEY ("FilterKey"); +const QLatin1StringView REGISTRY_FILTER_NAME ("FilterName"); +const QLatin1StringView REGISTRY_FILTER_VALUE ("FilterValue"); + +// Tab Torrent +const QLatin1StringView REGISTRY_TORRENT_ENABLED ("TorrentEnabled"); +const QLatin1StringView REGISTRY_TORRENT_SHARED ("TorrentShareFolderEnabled"); +const QLatin1StringView REGISTRY_TORRENT_DIR ("TorrentShareFolder"); +const QLatin1StringView REGISTRY_TORRENT_PEERS ("TorrentPeerList"); +const QLatin1StringView REGISTRY_TORRENT_ADVANCED ("TorrentAdvanced"); + +// Tab Advanced +const QLatin1StringView REGISTRY_CHECK_UPDATE ("CheckUpdate"); + + +#if defined Q_OS_WIN +const QLatin1StringView C_PROGRAM_NAME("yt-dlp.exe"); +#else +const QLatin1StringView C_PROGRAM_NAME("yt-dlp"); +#endif + +const QLatin1StringView C_WEBSITE_URL("https://github.com/yt-dlp/yt-dlp"); +const int C_EXIT_SUCCESS = 0; + +const QLatin1StringView C_NONE("none"); + +const QLatin1StringView C_WARNING_msg_header_01("WARNING:"); +const QLatin1StringView C_WARNING_msg_header_02("\\033[0;33mWARNING:\\033[0m"); +const QLatin1StringView C_ERROR_msg_header_01("ERROR:"); +const QLatin1StringView C_ERROR_msg_header_02("\\033[0;31mERROR:\\033[0m"); + +const QLatin1StringView C_WARNING_merge_output_format("Requested formats are incompatible for merge and will be merged into mkv."); + +const QLatin1StringView C_DOWNLOAD_msg_header("[download]"); +const QLatin1StringView C_DOWNLOAD_next_section("Destination:"); +const QLatin1StringView C_MERGER_msg_header("[Merger]"); + + +const QLatin1StringView THEME_DEFAULT("default"); +const QLatin1StringView THEME_FLAT("flat"); +const QLatin1StringView SCHEME_LIGHT("light"); +const QLatin1StringView SCHEME_DARK("dark"); + + +const QLatin1StringView CAPTION_DEFAULT("default"); +const QLatin1StringView CAPTION_AUTOMATIC("automatic"); + +#endif // CONSTANTS_H diff --git a/src/core/abstractdownloaditem.cpp b/src/core/abstractdownloaditem.cpp index 877c86c2..eb3a008e 100644 --- a/src/core/abstractdownloaditem.cpp +++ b/src/core/abstractdownloaditem.cpp @@ -16,6 +16,8 @@ #include "abstractdownloaditem.h" +#include + #include #include #include @@ -28,25 +30,14 @@ * */ -constexpr int timeout_update_msec = 150; // in milliseconds /*! * \brief Constructor */ AbstractDownloadItem::AbstractDownloadItem(QObject *parent) : QObject(parent) - , m_log(QString()) { connect(&m_updateInfoTimer, SIGNAL(timeout()), this, SLOT(updateInfo())); connect(&m_updateCountDownTimer, SIGNAL(timeout()), this, SLOT(updateInfo())); - - m_state = State::Idle; - - m_speed = -1; - m_bytesReceived = 0; - m_bytesTotal = 0; - - m_maxConnectionSegments = 4; - m_maxConnections = 1; } /****************************************************************************** @@ -139,7 +130,7 @@ qreal AbstractDownloadItem::speed() const int AbstractDownloadItem::progress() const { if (m_bytesTotal > 0) { - return qBound(0, qFloor(qreal(100 * m_bytesReceived) / m_bytesTotal), 100); + return qBound(0, qFloor(100 * static_cast(m_bytesReceived) / static_cast(m_bytesTotal)), 100); } if (m_state == Idle) { return 0; @@ -174,7 +165,7 @@ int AbstractDownloadItem::maxConnectionSegments() const void AbstractDownloadItem::setMaxConnectionSegments(int connectionSegments) { - if (connectionSegments > 0 && connectionSegments <= 10) { + if (connectionSegments > 0 && connectionSegments <= MAX_CONNECTION_SEGMENTS) { m_maxConnectionSegments = connectionSegments; } } @@ -321,13 +312,13 @@ void AbstractDownloadItem::tearDownResume() /* * This timer ticks each second, in order to update the remaining time information (countdown) */ - m_updateCountDownTimer.start(1000); + m_updateCountDownTimer.start(TIMEOUT_COUNT_DOWN); /* * This timer updates the speed/progress info. * It can be quicker than the countdown timer. */ - m_updateInfoTimer.start(timeout_update_msec); + m_updateInfoTimer.start(TIMEOUT_INFO); /* Start downloading now. */ m_state = Downloading; @@ -369,9 +360,9 @@ void AbstractDownloadItem::updateInfo(qsizetype bytesReceived, qsizetype bytesTo { m_bytesReceived = bytesReceived; m_bytesTotal = bytesTotal; - const int elapsed = m_downloadElapsedTimer.elapsed(); + auto elapsed = m_downloadElapsedTimer.elapsed(); if (elapsed > 0) { - m_speed = qreal(1000 * bytesReceived) / m_downloadElapsedTimer.elapsed(); + m_speed = 1000 * static_cast(bytesReceived) / static_cast(m_downloadElapsedTimer.elapsed()); } else { m_speed = qreal(-1); } @@ -388,12 +379,12 @@ void AbstractDownloadItem::updateInfo(qsizetype bytesReceived, qsizetype bytesTo void AbstractDownloadItem::updateInfo() { if (m_speed > 0 && m_bytesReceived > 0 && m_bytesTotal > 0) { - const int estimatedTime = qCeil(qreal(m_bytesTotal - m_bytesReceived) / m_speed); + auto estimatedTime = qCeil(static_cast(m_bytesTotal - m_bytesReceived) / m_speed); QTime time(0, 0, 0); - time = time.addSecs(estimatedTime); + time = time.addSecs(static_cast(estimatedTime)); m_remainingTime = time; } else { - m_remainingTime = QTime(); + m_remainingTime = {}; } emit changed(); } diff --git a/src/core/abstractdownloaditem.h b/src/core/abstractdownloaditem.h index bd08461a..e0476ee1 100644 --- a/src/core/abstractdownloaditem.h +++ b/src/core/abstractdownloaditem.h @@ -31,47 +31,47 @@ class AbstractDownloadItem : public QObject, public IDownloadItem Q_OBJECT public: - explicit AbstractDownloadItem(QObject *parent = Q_NULLPTR); - ~AbstractDownloadItem() noexcept Q_DECL_OVERRIDE = default; // IMPORTANT: virtual destructor + explicit AbstractDownloadItem(QObject *parent = nullptr); + ~AbstractDownloadItem() noexcept override = default; // IMPORTANT: virtual destructor - State state() const Q_DECL_OVERRIDE; + State state() const override; void setState(State state); QString stateToString() const; const char* state_c_str() const; - qsizetype bytesReceived() const Q_DECL_OVERRIDE; + qsizetype bytesReceived() const override; void setBytesReceived(qsizetype bytesReceived); - qsizetype bytesTotal() const Q_DECL_OVERRIDE; + qsizetype bytesTotal() const override; void setBytesTotal(qsizetype bytesTotal); - qreal speed() const Q_DECL_OVERRIDE; - int progress() const Q_DECL_OVERRIDE; + qreal speed() const override; + int progress() const override; QString errorMessage() const; void setErrorMessage(const QString &message); - int maxConnectionSegments() const Q_DECL_OVERRIDE; + int maxConnectionSegments() const override; void setMaxConnectionSegments(int connectionSegments); - int maxConnections() const Q_DECL_OVERRIDE; + int maxConnections() const override; void setMaxConnections(int connections); - QString log() const Q_DECL_OVERRIDE; + QString log() const override; void setLog(const QString &log); void logInfo(const QString &message); - bool isResumable() const Q_DECL_OVERRIDE; - bool isPausable() const Q_DECL_OVERRIDE; - bool isCancelable() const Q_DECL_OVERRIDE; - bool isDownloading() const Q_DECL_OVERRIDE; + bool isResumable() const override; + bool isPausable() const override; + bool isCancelable() const override; + bool isDownloading() const override; QTime remainingTime(); - void setReadyToResume() Q_DECL_OVERRIDE; + void setReadyToResume() override; - void pause() Q_DECL_OVERRIDE; - void stop() Q_DECL_OVERRIDE; + void pause() override; + void stop() override; void beginResume(); bool checkResume(bool connected); @@ -94,24 +94,23 @@ private slots: void updateInfo(); private: - State m_state; + State m_state = State::Idle; - qreal m_speed; - qsizetype m_bytesReceived; - qsizetype m_bytesTotal; + qreal m_speed = -1; + qsizetype m_bytesReceived = 0; + qsizetype m_bytesTotal = 0; - QString m_errorMessage; + QString m_errorMessage = {}; - int m_maxConnectionSegments; - int m_maxConnections; + int m_maxConnectionSegments = 4; + int m_maxConnections = 1; - QString m_log; + QString m_log = {}; QElapsedTimer m_downloadElapsedTimer; QTime m_remainingTime; QTimer m_updateInfoTimer; QTimer m_updateCountDownTimer; - }; #endif // CORE_ABSTRACT_DOWNLOAD_ITEM_H diff --git a/src/core/abstractsettings.cpp b/src/core/abstractsettings.cpp index 6f5c7b57..2493e2c7 100644 --- a/src/core/abstractsettings.cpp +++ b/src/core/abstractsettings.cpp @@ -16,26 +16,19 @@ #include "abstractsettings.h" +#include + #include #include #include #include #include -/* - * Remark: - * Characters '<' and '>' are unlikely to be used as value for data or directory path. - * If a collision appears, the only risk is to reset the faulty parameter - * to its default value. - */ -static const QLatin1String UNDEFINED (""); -static const QLatin1String VALUE_TRUE (""); -static const QLatin1String VALUE_FALSE (""); /* * Helper methods */ -static QString boolToString(bool b) { return b ? VALUE_TRUE : VALUE_FALSE; } +static QString boolToString(bool value) { return value ? VALUE_TRUE : VALUE_FALSE; } static bool stringToBool(const QString &str) { return str == VALUE_TRUE; } static QString intToString(int value) { return QString::number(value); } @@ -77,9 +70,9 @@ void AbstractSettings::endRestoreDefault() void AbstractSettings::readSettings() { QSettings settings; - settings.beginGroup(QLatin1String("Preference")); - foreach (auto item, m_items) { - const QString value = settings.value(uniqueRegisterKey(item), UNDEFINED).toString(); + settings.beginGroup(SETTING_GROUP_PREFERENCE); + for (auto item : m_items) { + auto value = settings.value(uniqueRegisterKey(item), UNDEFINED).toString(); item->value = (value != UNDEFINED) ? value : item->defaultValue; } settings.endGroup(); @@ -89,9 +82,9 @@ void AbstractSettings::readSettings() void AbstractSettings::writeSettings() { QSettings settings; - settings.beginGroup(QLatin1String("Preference")); - foreach (auto item, m_items) { - const QString name = uniqueRegisterKey(item); + settings.beginGroup(SETTING_GROUP_PREFERENCE); + for (auto item : m_items) { + auto name = uniqueRegisterKey(item); if (item->value != item->defaultValue || settings.contains(name)) { settings.setValue(name, item->value); } @@ -103,7 +96,7 @@ void AbstractSettings::writeSettings() ******************************************************************************/ QString AbstractSettings::uniqueRegisterKey(const SettingsItem *item) const { - Q_ASSERT(item != Q_NULLPTR); + Q_ASSERT(item != nullptr); switch (item->keyType) { case BOOL: return QString("%0_bool").arg(item->key); @@ -174,9 +167,9 @@ void AbstractSettings::setSettingString(const QString &key, const QString &value QStringList AbstractSettings::getSettingStringList(const QString &key) const { QStringList ret; - for (int i = 0; i < m_items.count(); ++i) { - const QString subkey = QString("%0%1").arg(key, QString::number(i)); - foreach (auto item, m_items) { + for (auto i = 0; i < m_items.count(); ++i) { + auto subkey = QString("%0%1").arg(key, QString::number(i)); + for (auto item : m_items) { if (item->key == subkey) { ret << (m_default ? item->defaultValue : item->value); } @@ -187,18 +180,18 @@ QStringList AbstractSettings::getSettingStringList(const QString &key) const void AbstractSettings::addDefaultSettingStringList(const QString &key, const QStringList &defaultValue) { - for (int i = 0; i < defaultValue.count(); ++i) { - const QString subkey = QString("%0%1").arg(key, QString::number(i)); - const QString& subvalue = defaultValue.at(i); + for (auto i = 0; i < defaultValue.count(); ++i) { + auto subkey = QString("%0%1").arg(key, QString::number(i)); + auto subvalue = defaultValue.at(i); addDefaultSettingString(subkey, subvalue); } } void AbstractSettings::setSettingStringList(const QString &key, const QStringList &value) { - for (int i = 0; i < value.count(); ++i) { - const QString subkey = QString("%0%1").arg(key, QString::number(i)); - const QString& subvalue = value.at(i); + for (auto i = 0; i < value.count(); ++i) { + auto subkey = QString("%0%1").arg(key, QString::number(i)); + auto subvalue = value.at(i); setSettingString(subkey, subvalue); } } @@ -255,7 +248,7 @@ void AbstractSettings::_q_addDefaultSetting(const QString &key, if (defaultValue.isNull() || defaultValue == UNDEFINED) { throw IllegalValueException(); } - foreach (auto item, m_items) { + for (auto item : m_items) { if (item->keyType == keyType && item->key == key) { item->defaultValue = defaultValue; return; @@ -273,7 +266,7 @@ QString AbstractSettings::_q_getSetting(const QString &key, KeyType keyType) con if (key.isEmpty() || key == UNDEFINED) { throw IllegalKeyException(); } - foreach (auto item, m_items) { + for (auto item : m_items) { if (item->key == key) { if (item->keyType != keyType) { throw WrongTypeException(); @@ -294,7 +287,7 @@ void AbstractSettings::_q_setSetting(const QString &key, if (value.isNull() || value == UNDEFINED) { throw IllegalValueException(); } - foreach (auto item, m_items) { + for (auto item : m_items) { if (item->key == key) { if (item->keyType != keyType) { throw WrongTypeException(); diff --git a/src/core/abstractsettings.h b/src/core/abstractsettings.h index cff4e140..e0499dc1 100644 --- a/src/core/abstractsettings.h +++ b/src/core/abstractsettings.h @@ -33,8 +33,8 @@ class AbstractSettings : public QObject struct SettingsItem; public: - explicit AbstractSettings(QObject *parent = Q_NULLPTR); - ~AbstractSettings() Q_DECL_OVERRIDE; + explicit AbstractSettings(QObject *parent = nullptr); + ~AbstractSettings() override; void beginRestoreDefault(); void endRestoreDefault(); diff --git a/src/core/checkabletablemodel.cpp b/src/core/checkabletablemodel.cpp index 44f1c6be..3875a621 100644 --- a/src/core/checkabletablemodel.cpp +++ b/src/core/checkabletablemodel.cpp @@ -38,7 +38,7 @@ QList CheckableTableModel::checkedRows() const { QSet rows; auto indexes = m_checkedIndexes.values(); - foreach (auto index, indexes) { + for (auto index : indexes) { rows.insert(index.row()); } auto list = rows.values(); @@ -57,12 +57,12 @@ QList CheckableTableModel::checkedRows() const QVariant CheckableTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (role == CheckStateRole) { return m_checkedIndexes.contains(index); } - return QVariant(); + return {}; } bool CheckableTableModel::setData(const QModelIndex &index, const QVariant &value, int role) @@ -71,7 +71,7 @@ bool CheckableTableModel::setData(const QModelIndex &index, const QVariant &valu return false; } if (index.column() == 0 && role == CheckStateRole) { - const bool checked = value.toBool(); + auto checked = value.toBool(); if (m_checkedIndexes.contains(index) == checked) { return true; // Successful } @@ -82,8 +82,8 @@ bool CheckableTableModel::setData(const QModelIndex &index, const QVariant &valu } emit checkStateChanged(index, checked); - QModelIndex topLeft = index; - QModelIndex bottomRight = this->index(index.row(), columnCount()); + auto topLeft = index; + auto bottomRight = this->index(index.row(), columnCount()); emit dataChanged(topLeft, bottomRight); return true; } diff --git a/src/core/checkabletablemodel.h b/src/core/checkabletablemodel.h index 5939bd9f..527e347d 100644 --- a/src/core/checkabletablemodel.h +++ b/src/core/checkabletablemodel.h @@ -30,13 +30,13 @@ class CheckableTableModel : public QAbstractTableModel }; explicit CheckableTableModel(QObject *parent); - ~CheckableTableModel() Q_DECL_OVERRIDE = default; + ~CheckableTableModel() override = default; virtual void clear(); - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) Q_DECL_OVERRIDE; - // Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; + QVariant data(const QModelIndex &index, int role) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + // Qt::ItemFlags flags(const QModelIndex &index) const override; signals: void checkStateChanged(QModelIndex index, bool checked); diff --git a/src/core/downloadengine.cpp b/src/core/downloadengine.cpp index 64dc109a..3c1ed523 100644 --- a/src/core/downloadengine.cpp +++ b/src/core/downloadengine.cpp @@ -16,13 +16,12 @@ #include "downloadengine.h" +#include #include #include #include -constexpr int selection_display_limit = 10; -constexpr int msec_speed_display_time = 2000; DownloadEngine::DownloadEngine(QObject *parent) : QObject(parent) , m_maxSimultaneousDownloads(4) @@ -48,10 +47,10 @@ DownloadEngine::~DownloadEngine() /****************************************************************************** ******************************************************************************/ -int DownloadEngine::downloadingCount() const +qsizetype DownloadEngine::downloadingCount() const { - int count = 0; - foreach (auto item, m_items) { + auto count = 0; + for (auto item : m_items) { if (item->isDownloading()) { count++; } @@ -62,10 +61,10 @@ int DownloadEngine::downloadingCount() const void DownloadEngine::startNext(IDownloadItem * /*item*/) { if (downloadingCount() < m_maxSimultaneousDownloads) { - foreach (auto item, m_items) { + for (auto item : m_items) { if (item->state() == IDownloadItem::Idle) { item->resume(); - startNext(Q_NULLPTR); + startNext(nullptr); break; } } @@ -74,7 +73,7 @@ void DownloadEngine::startNext(IDownloadItem * /*item*/) /****************************************************************************** ******************************************************************************/ -int DownloadEngine::count() const +qsizetype DownloadEngine::count() const { return m_items.count(); } @@ -84,7 +83,7 @@ int DownloadEngine::count() const void DownloadEngine::clear() { clearSelection(); - remove(m_items); + removeItems(m_items); } /****************************************************************************** @@ -94,7 +93,7 @@ void DownloadEngine::append(const QList &items, bool started) if (items.isEmpty()) { return; } - foreach (auto item, items) { + for (auto item : items) { auto downloadItem = dynamic_cast(item); if (!downloadItem) { return; @@ -102,8 +101,7 @@ void DownloadEngine::append(const QList &items, bool started) connect(downloadItem, SIGNAL(changed()), this, SLOT(onChanged())); connect(downloadItem, SIGNAL(finished()), this, SLOT(onFinished())); - connect(downloadItem, SIGNAL(renamed(QString, QString, bool)), - this, SLOT(onRenamed(QString, QString, bool))); + connect(downloadItem, SIGNAL(renamed(QString,QString,bool)), this, SLOT(onRenamed(QString,QString,bool))); if (started) { if (downloadItem->isResumable()) { @@ -120,24 +118,29 @@ void DownloadEngine::append(const QList &items, bool started) emit jobAppended(items); if (started) { - startNext(Q_NULLPTR); + startNext(nullptr); } } void DownloadEngine::remove(const QList &items) +{ + removeItems(items); +} + +void DownloadEngine::removeItems(const QList &items) { if (items.isEmpty()) { return; } /* First, deselect */ beginSelectionChange(); - foreach (auto item, items) { + for (auto item : items) { setSelected(item, false); } endSelectionChange(); /* Then, remove */ - foreach (auto item, items) { + for (auto item : items) { cancel(item); // stop the reply first m_items.removeAll(item); auto downloadItem = dynamic_cast(item); @@ -150,14 +153,14 @@ void DownloadEngine::remove(const QList &items) void DownloadEngine::updateItems(const QList &items) { - foreach (auto item, items) { + for (auto item : items) { emit jobStateChanged(item); } } /****************************************************************************** ******************************************************************************/ -const IDownloadItem* DownloadEngine::clientForRow(int row) const +const IDownloadItem* DownloadEngine::clientForRow(qsizetype row) const { Q_ASSERT(row >=0 && row < m_items.count()); return m_items.at(row); @@ -186,8 +189,8 @@ static inline QList filter(const QList &items, const QList &states) { QList list; - foreach (auto item, items) { - foreach (auto state, states) { + for (auto item : items) { + for (auto state : states) { if (item->state() == state) { list.append(item); } @@ -241,12 +244,12 @@ void DownloadEngine::onSpeedTimerTimeout() qreal DownloadEngine::totalSpeed() { qreal speed = 0; - foreach (auto item, m_items) { + for (auto item : m_items) { speed += qMax(item->speed(), qreal(0)); } if (speed > 0) { m_previouSpeed = speed; - m_speedTimer.start(msec_speed_display_time); + m_speedTimer.start(MSEC_SPEED_DISPLAY_TIME); } return m_previouSpeed; } @@ -336,12 +339,12 @@ QString DownloadEngine::selectionToString() const { QString ret; int count = 0; - foreach (auto item, m_selectedItems) { + for (auto item : m_selectedItems) { ret += item->localFileName(); ret += "\n"; count++; - if (count > selection_display_limit) { - ret += tr("... (%0 others)").arg(m_selectedItems.count() - selection_display_limit); + if (count > SELECTION_DISPLAY_LIMIT) { + ret += tr("... (%0 others)").arg(m_selectedItems.count() - SELECTION_DISPLAY_LIMIT); break; } } @@ -351,7 +354,7 @@ QString DownloadEngine::selectionToString() const QString DownloadEngine::selectionToClipboard() const { QString ret; - foreach (auto item, m_selectedItems) { + for (auto item : m_selectedItems) { ret += item->sourceUrl().toString(); ret += "\n"; } @@ -378,7 +381,7 @@ void DownloadEngine::sortSelectionByIndex() if (m_selectedItems.isEmpty()) { return; } - QMap map; + QMap map; for (auto selectedItem : m_selectedItems) { auto index = m_items.indexOf(selectedItem); map.insert(index, selectedItem); @@ -386,33 +389,25 @@ void DownloadEngine::sortSelectionByIndex() m_selectedItems = map.values(); } -void DownloadEngine::moveUpTo(int targetIndex) +void DownloadEngine::moveUpTo(qsizetype targetIndex) { - for (int i = 0, total = m_selectedItems.size(); i < total; ++i) { + for (auto i = 0; i < m_selectedItems.size(); ++i) { auto indexToMove = m_items.indexOf(m_selectedItems.at(i)); - for (int j = indexToMove; j > targetIndex + i; --j) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + for (auto j = indexToMove; j > targetIndex + i; --j) { m_items.swapItemsAt(j, j - 1); -#else - m_items.swap(j, j - 1); -#endif } } emit sortChanged(); } -void DownloadEngine::moveDownTo(int targetIndex) +void DownloadEngine::moveDownTo(qsizetype targetIndex) { auto count = m_selectedItems.size() - 1; - for (int i = count; i >= 0; --i) { - auto i2 = count - i; + for (auto i = count; i >= 0; --i) { + auto k = count - i; auto indexToMove = m_items.indexOf(m_selectedItems.at(i)); - for (int j = indexToMove; j < targetIndex - i2; ++j) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) + for (auto j = indexToMove; j < targetIndex - k; ++j) { m_items.swapItemsAt(j, j + 1); -#else - m_items.swap(j, j + 1); -#endif } } emit sortChanged(); @@ -461,9 +456,9 @@ void DownloadEngine::moveCurrentBottom() ******************************************************************************/ void DownloadEngine::oneMoreSegment() { - foreach (auto item, selection()) { + for (auto item : selection()) { auto downloadItem = dynamic_cast(item); - int segments = downloadItem->maxConnectionSegments(); + auto segments = downloadItem->maxConnectionSegments(); segments++; downloadItem->setMaxConnectionSegments(segments); } @@ -471,9 +466,9 @@ void DownloadEngine::oneMoreSegment() void DownloadEngine::oneFewerSegment() { - foreach (auto item, selection()) { + for (auto item : selection()) { auto downloadItem = dynamic_cast(item); - int segments = downloadItem->maxConnectionSegments(); + auto segments = downloadItem->maxConnectionSegments(); segments--; downloadItem->setMaxConnectionSegments(segments); } @@ -488,12 +483,12 @@ void DownloadEngine::oneFewerSegment() */ IDownloadItem* DownloadEngine::createItem(const QUrl &/*url*/) { - return Q_NULLPTR; + return nullptr; } /*! * \sa DownloadEngine::createItem() */ IDownloadItem* DownloadEngine::createTorrentItem(const QUrl &/*url*/) { - return Q_NULLPTR; + return nullptr; } diff --git a/src/core/downloadengine.h b/src/core/downloadengine.h index b33d8673..7f102297 100644 --- a/src/core/downloadengine.h +++ b/src/core/downloadengine.h @@ -32,17 +32,19 @@ class DownloadEngine : public QObject public: explicit DownloadEngine(QObject *parent = nullptr); - ~DownloadEngine() Q_DECL_OVERRIDE; + ~DownloadEngine() override; /* Queue Management */ - int count() const; + qsizetype count() const; void clear(); virtual void append(const QList &items, bool started = false); virtual void remove(const QList &items); + + void removeItems(const QList &items); void updateItems(const QList &items); - const IDownloadItem* clientForRow(int row) const; + const IDownloadItem* clientForRow(qsizetype row) const; int maxSimultaneousDownloads() const; void setMaxSimultaneousDownloads(int number); @@ -118,14 +120,14 @@ private slots: // Pool int m_maxSimultaneousDownloads; - int downloadingCount() const; + qsizetype downloadingCount() const; QList m_selectedItems; bool m_selectionAboutToChange; void sortSelectionByIndex(); - void moveUpTo(int targetIndex); - void moveDownTo(int targetIndex); + void moveUpTo(qsizetype targetIndex); + void moveDownTo(qsizetype targetIndex); }; #endif // CORE_DOWNLOAD_ENGINE_H diff --git a/src/core/downloaditem.cpp b/src/core/downloaditem.cpp index 8cfd9678..c3eddeef 100644 --- a/src/core/downloaditem.cpp +++ b/src/core/downloaditem.cpp @@ -27,6 +27,8 @@ #include #include +using namespace Qt::Literals::StringLiterals; + DownloadItemPrivate::DownloadItemPrivate(DownloadItem *qq) : q(qq) { @@ -45,13 +47,13 @@ DownloadItem::~DownloadItem() { if (d->file) { d->file->deleteLater(); - d->file = Q_NULLPTR; + d->file = nullptr; } if (d->reply) { d->reply->abort(); d->reply->deleteLater(); - d->reply = Q_NULLPTR; + d->reply = nullptr; } } @@ -63,7 +65,7 @@ void DownloadItem::resume() this->beginResume(); - File::OpenFlag flag = d->file->open(d->resource); + auto flag = d->file->open(d->resource); if (flag == File::Skip) { setState(Skipped); @@ -72,22 +74,20 @@ void DownloadItem::resume() return; } - const bool connected = flag == File::Open; + auto connected = flag == File::Open; /* Prepare the connection, try to contact the server */ if (this->checkResume(connected)) { - QUrl url(d->resource->url()); + auto url = d->resource->url_TODO(); d->reply = d->downloadManager->networkManager()->get(url); d->reply->setParent(this); /* Signals/Slots of QNetworkReply */ connect(d->reply, SIGNAL(metaDataChanged()), this, SLOT(onMetaDataChanged())); - connect(d->reply, SIGNAL(downloadProgress(qint64, qint64)), - this, SLOT(onDownloadProgress(qint64, qint64))); + connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64,qint64))); connect(d->reply, SIGNAL(redirected(QUrl)), this, SLOT(onRedirected(QUrl))); - connect(d->reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), - this, SLOT(onErrorOccurred(QNetworkReply::NetworkError))); + connect(d->reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(onErrorOccurred(QNetworkReply::NetworkError))); connect(d->reply, SIGNAL(finished()), this, SLOT(onFinished())); /* Signals/Slots of QIODevice */ @@ -112,7 +112,7 @@ void DownloadItem::stop() if (d->reply) { d->reply->abort(); d->reply->deleteLater(); - d->reply = Q_NULLPTR; + d->reply = nullptr; } AbstractDownloadItem::stop(); } @@ -121,11 +121,14 @@ void DownloadItem::stop() ******************************************************************************/ void DownloadItem::rename(const QString &newName) { - QString newCustomFileName = newName.trimmed().isEmpty() ? QString() : newName; - const QString oldPath = d->resource->localFileFullPath(d->resource->customFileName()); - const QString newPath = d->resource->localFileFullPath(newCustomFileName); + QString newCustomFileName; + if (!newName.trimmed().isEmpty()) { + newCustomFileName = newName; + } + auto oldPath = d->resource->localFileFullPath(d->resource->customFileName()); + auto newPath = d->resource->localFileFullPath(newCustomFileName); - const QString oldFileName = d->resource->fileName(); + auto oldFileName = d->resource->fileName(); if (oldPath == newPath) { return; @@ -143,7 +146,7 @@ void DownloadItem::rename(const QString &newName) d->file->rename(d->resource); } } - const QString newFileName = success ? d->resource->fileName() : newName; + auto newFileName = success ? d->resource->fileName() : newName; emit renamed(oldFileName, newFileName, success); } @@ -154,8 +157,8 @@ void DownloadItem::onMetaDataChanged() if (d->reply) { auto rawNewUrl = d->reply->header(QNetworkRequest::LocationHeader); if (rawNewUrl.isValid()) { - const QUrl oldUrl = d->resource->url(); - const QUrl newUrl = rawNewUrl.toUrl(); + auto oldUrl = d->resource->url_TODO(); + auto newUrl = rawNewUrl.toUrl(); /* Check if the metadata change is a redirection */ if (newUrl.isValid() && oldUrl.isValid() && oldUrl != newUrl) { logInfo(QString("HTTP redirect: '%0' to '%1'.").arg(oldUrl.toString(), newUrl.toString())); @@ -247,7 +250,7 @@ void DownloadItem::onFinished() } if (d->reply) { d->reply->deleteLater(); - d->reply = Q_NULLPTR; + d->reply = nullptr; } this->finish(); } @@ -275,10 +278,8 @@ QString DownloadItem::statusToHttp(QNetworkReply::NetworkError error) case QNetworkReply::TemporaryNetworkFailureError: return tr("3xx Redirect temporary network failure"); case QNetworkReply::NetworkSessionFailedError: return tr("3xx Redirect network session failed"); case QNetworkReply::BackgroundRequestNotAllowedError: return tr("3xx Redirect background request not allowed"); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) case QNetworkReply::TooManyRedirectsError: return tr("3xx Too many redirects"); case QNetworkReply::InsecureRedirectError: return tr("3xx Insecure redirect"); -#endif case QNetworkReply::UnknownNetworkError: return tr("3xx Unknown redirect error"); // proxy errors (101-199): @@ -373,7 +374,7 @@ QUrl DownloadItem::sourceUrl() const */ QString DownloadItem::localFullFileName() const { - const QUrl target = d->resource->localFileUrl(); + auto target = d->resource->localFileUrl(); return target.toLocalFile(); } @@ -382,7 +383,7 @@ QString DownloadItem::localFullFileName() const */ QString DownloadItem::localFileName() const { - const QUrl target = d->resource->localFileUrl(); + auto target = d->resource->localFileUrl(); const QFileInfo fi(target.toLocalFile()); return fi.fileName(); } @@ -392,7 +393,7 @@ QString DownloadItem::localFileName() const */ QString DownloadItem::localFilePath() const { - const QUrl target = d->resource->localFileUrl(); + auto target = d->resource->localFileUrl(); const QFileInfo fi(target.toLocalFile()); return fi.absolutePath(); } diff --git a/src/core/downloaditem.h b/src/core/downloaditem.h index 810feeea..757cd6ee 100644 --- a/src/core/downloaditem.h +++ b/src/core/downloaditem.h @@ -35,25 +35,25 @@ class DownloadItem : public AbstractDownloadItem public: DownloadItem(DownloadManager *downloadManager); - ~DownloadItem() Q_DECL_OVERRIDE; + ~DownloadItem() override; /* Resource to download */ ResourceItem* resource() const; virtual void setResource(ResourceItem *resource); /* Convenient */ - QUrl sourceUrl() const Q_DECL_OVERRIDE; - QString localFileName() const Q_DECL_OVERRIDE; - QString localFullFileName() const Q_DECL_OVERRIDE; - QString localFilePath() const Q_DECL_OVERRIDE; - QUrl localFileUrl() const Q_DECL_OVERRIDE; - QUrl localDirUrl() const Q_DECL_OVERRIDE; + QUrl sourceUrl() const override; + QString localFileName() const override; + QString localFullFileName() const override; + QString localFilePath() const override; + QUrl localFileUrl() const override; + QUrl localDirUrl() const override; - void resume() Q_DECL_OVERRIDE; - void pause() Q_DECL_OVERRIDE; - void stop() Q_DECL_OVERRIDE; + void resume() override; + void pause() override; + void stop() override; - void rename(const QString &newName) Q_DECL_OVERRIDE; + void rename(const QString &newName) override; private slots: void onMetaDataChanged(); diff --git a/src/core/downloaditem_p.h b/src/core/downloaditem_p.h index 45eb8da6..e44c9790 100644 --- a/src/core/downloaditem_p.h +++ b/src/core/downloaditem_p.h @@ -30,9 +30,9 @@ class DownloadItemPrivate public: DownloadItemPrivate(DownloadItem *qq); - DownloadManager *downloadManager{Q_NULLPTR}; - ResourceItem *resource{Q_NULLPTR}; - QNetworkReply *reply{Q_NULLPTR}; + DownloadManager *downloadManager{nullptr}; + ResourceItem *resource{nullptr}; + QNetworkReply *reply{nullptr}; File *file; DownloadItem *q; diff --git a/src/core/downloadmanager.cpp b/src/core/downloadmanager.cpp index f928e766..3b89bb79 100644 --- a/src/core/downloadmanager.cpp +++ b/src/core/downloadmanager.cpp @@ -16,6 +16,7 @@ #include "downloadmanager.h" +#include #include #include #include @@ -30,7 +31,8 @@ #include #include -constexpr int msec_auto_save = 3000; ///< Autosave the queue every 3 seconds. +using namespace Qt::Literals::StringLiterals; + /*! * \class DownloadManager @@ -45,9 +47,6 @@ constexpr int msec_auto_save = 3000; ///< Autosave the queue every 3 seconds. DownloadManager::DownloadManager(QObject *parent) : DownloadEngine(parent) , m_networkManager(new NetworkManager(this)) - , m_settings(Q_NULLPTR) - , m_dirtyQueueTimer(Q_NULLPTR) - , m_queueFile(QString()) { /* Auto save of the queue */ connect(this, SIGNAL(jobAppended(DownloadRange)), this, SLOT(onQueueChanged(DownloadRange))); @@ -105,7 +104,7 @@ void DownloadManager::loadQueue() Session::read(downloadItems, m_queueFile, this); QList abstractItems; - foreach (auto item, downloadItems) { + for (auto item : downloadItems) { // Cast items of the list abstractItems.append(static_cast(item)); } @@ -119,12 +118,12 @@ void DownloadManager::saveQueue() if (!m_queueFile.isEmpty()) { QList items; - const bool skipCompleted = m_settings->isRemoveCompletedEnabled(); - const bool skipCanceled = m_settings->isRemoveCanceledEnabled(); - const bool skipPaused = m_settings->isRemovePausedEnabled(); + auto skipCompleted = m_settings->isRemoveCompletedEnabled(); + auto skipCanceled = m_settings->isRemoveCanceledEnabled(); + auto skipPaused = m_settings->isRemovePausedEnabled(); - QList abstractItems = downloadItems(); - foreach (auto abstractItem, abstractItems) { + auto abstractItems = downloadItems(); + for (auto abstractItem : abstractItems) { auto item = dynamic_cast(abstractItem); if (item) { switch (item->state()) { @@ -176,7 +175,7 @@ void DownloadManager::onQueueChanged() connect(m_dirtyQueueTimer, SIGNAL(timeout()), SLOT(saveQueue())); } if (!m_dirtyQueueTimer->isActive()) { - m_dirtyQueueTimer->start(msec_auto_save); + m_dirtyQueueTimer->start(MSEC_AUTO_SAVE); } } @@ -212,17 +211,17 @@ inline ResourceItem* DownloadManager::createResourceItem(const QUrl &url) { QSettings settings; settings.beginGroup("Wizard"); - const QString path = settings.value("Path", QString()).toString(); - const QString mask = settings.value("Mask", QString()).toString(); + auto path = settings.value("Path"_L1, {}).toString(); + auto mask = settings.value("Mask"_L1, {}).toString(); settings.endGroup(); auto resource = new ResourceItem(); resource->setUrl(url.toString().toUtf8()); - resource->setCustomFileName(QString()); - resource->setReferringPage(QString()); - resource->setDescription(QString()); + resource->setCustomFileName({}); + resource->setReferringPage({}); + resource->setDescription({}); resource->setDestination(path); resource->setMask(mask); - resource->setCheckSum(QString()); + resource->setCheckSum({}); return resource; } diff --git a/src/core/downloadmanager.h b/src/core/downloadmanager.h index 112bea18..8753767d 100644 --- a/src/core/downloadmanager.h +++ b/src/core/downloadmanager.h @@ -35,7 +35,7 @@ class DownloadManager : public DownloadEngine public: explicit DownloadManager(QObject *parent); - ~DownloadManager() Q_DECL_OVERRIDE; + ~DownloadManager() override; /* Settings */ Settings* settings() const; @@ -45,8 +45,8 @@ class DownloadManager : public DownloadEngine NetworkManager* networkManager() const; /* Utility */ - IDownloadItem* createItem(const QUrl &url) Q_DECL_OVERRIDE; - IDownloadItem* createTorrentItem(const QUrl &url) Q_DECL_OVERRIDE; + IDownloadItem* createItem(const QUrl &url) override; + IDownloadItem* createTorrentItem(const QUrl &url) override; private slots: void onSettingsChanged(); @@ -61,11 +61,11 @@ private slots: private: /* Network parameters (SSL, Proxy, UserAgent...) */ NetworkManager *m_networkManager; - Settings *m_settings; + Settings *m_settings = nullptr; /* Crash Recovery */ - QTimer* m_dirtyQueueTimer; - QString m_queueFile; + QTimer* m_dirtyQueueTimer = nullptr; + QString m_queueFile = {}; inline ResourceItem* createResourceItem(const QUrl &url); }; diff --git a/src/core/downloadstreamitem.cpp b/src/core/downloadstreamitem.cpp index e2021f24..aed8b00c 100644 --- a/src/core/downloadstreamitem.cpp +++ b/src/core/downloadstreamitem.cpp @@ -25,7 +25,7 @@ ******************************************************************************/ DownloadStreamItem::DownloadStreamItem(DownloadManager *downloadManager) : DownloadItem(downloadManager) - , m_stream(Q_NULLPTR) + , m_stream(nullptr) { } @@ -45,18 +45,18 @@ void DownloadStreamItem::resume() return; } - const bool connected = flag == File::Open; + auto connected = flag == File::Open; /* Prepare the connection, try to contact the server */ if (this->checkResume(connected)) { if (m_stream) { m_stream->deleteLater(); - m_stream = Q_NULLPTR; + m_stream = nullptr; } m_stream = new Stream(this); - const QString outputPath = localFullFileName(); + auto outputPath = localFullFileName(); m_stream->setLocalFullOutputPath(outputPath); m_stream->setUrl(resource()->url()); @@ -67,7 +67,7 @@ void DownloadStreamItem::resume() m_stream->setConfig(resource()->streamConfig()); connect(m_stream, SIGNAL(downloadMetadataChanged()), this, SLOT(onMetaDataChanged())); - connect(m_stream, SIGNAL(downloadProgress(qsizetype, qsizetype)), this, SLOT(onDownloadProgress(qsizetype, qsizetype))); + connect(m_stream, SIGNAL(downloadProgress(qsizetype,qsizetype)), this, SLOT(onDownloadProgress(qsizetype,qsizetype))); connect(m_stream, SIGNAL(downloadError(QString)), this, SLOT(onError(QString))); connect(m_stream, SIGNAL(downloadFinished()), this, SLOT(onFinished())); @@ -93,7 +93,7 @@ void DownloadStreamItem::stop() if (m_stream) { m_stream->abort(); m_stream->deleteLater(); - m_stream = Q_NULLPTR; + m_stream = nullptr; } AbstractDownloadItem::stop(); } diff --git a/src/core/downloadstreamitem.h b/src/core/downloadstreamitem.h index 44ef3dc9..8b022d25 100644 --- a/src/core/downloadstreamitem.h +++ b/src/core/downloadstreamitem.h @@ -31,11 +31,11 @@ class DownloadStreamItem : public DownloadItem public: DownloadStreamItem(DownloadManager *downloadManager); - ~DownloadStreamItem() Q_DECL_OVERRIDE = default; + ~DownloadStreamItem() override = default; - void resume() Q_DECL_OVERRIDE; - void pause() Q_DECL_OVERRIDE; - void stop() Q_DECL_OVERRIDE; + void resume() override; + void pause() override; + void stop() override; private slots: void onMetaDataChanged(); diff --git a/src/core/downloadtorrentitem.h b/src/core/downloadtorrentitem.h index e51337f6..2c8fb6a5 100644 --- a/src/core/downloadtorrentitem.h +++ b/src/core/downloadtorrentitem.h @@ -32,15 +32,15 @@ class DownloadTorrentItem : public DownloadItem public: DownloadTorrentItem(DownloadManager *downloadManager); - ~DownloadTorrentItem() Q_DECL_OVERRIDE = default; + ~DownloadTorrentItem() override = default; - void setResource(ResourceItem *resource) Q_DECL_OVERRIDE; + void setResource(ResourceItem *resource) override; - void resume() Q_DECL_OVERRIDE; - void pause() Q_DECL_OVERRIDE; - void stop() Q_DECL_OVERRIDE; + void resume() override; + void pause() override; + void stop() override; - void rename(const QString &newName) Q_DECL_OVERRIDE; + void rename(const QString &newName) override; Torrent* torrent() const; diff --git a/src/core/file.cpp b/src/core/file.cpp index fb9bdade..c85794dc 100644 --- a/src/core/file.cpp +++ b/src/core/file.cpp @@ -28,13 +28,13 @@ #include #include -static IFileAccessManager *s_fileAccessManager = Q_NULLPTR; +static IFileAccessManager *s_fileAccessManager = nullptr; static ExistingFileOption existingFileOption() { - ExistingFileOption option = ExistingFileOption::Overwrite; + auto option = ExistingFileOption::Overwrite; if (s_fileAccessManager) { - const Settings* settings = s_fileAccessManager->settings(); + auto settings = s_fileAccessManager->settings(); if (settings) { option = settings->existingFileOption(); } @@ -66,10 +66,10 @@ void File::setFileAccessManager(IFileAccessManager *manager) File::OpenFlag File::open(ResourceItem *resource) { Q_ASSERT(resource); - const QUrl target = resource->localFileUrl(); - const QString fileName = target.toLocalFile(); + auto target = resource->localFileUrl(); + auto fileName = target.toLocalFile(); - const OpenFlag flag = open(fileName); + auto flag = open(fileName); resource->setCustomFileName(customFileName()); return flag; } @@ -78,14 +78,14 @@ File::OpenFlag File::open(const QString &fileName) { // Check Path const QFileInfo fi(fileName); - const QString localFilePath = fi.absolutePath(); + auto localFilePath = fi.absolutePath(); QDir().mkpath(localFilePath); // Check Existing File - QString safeFileName = fileName; + auto safeFileName = fileName; if (QFile::exists(safeFileName)) { - ExistingFileOption option = existingFileOption(); + auto option = existingFileOption(); while (s_fileAccessManager && option == ExistingFileOption::Ask) { option = s_fileAccessManager->aboutToModify(safeFileName); @@ -144,7 +144,7 @@ bool File::rename(ResourceItem *resource) inputFile.close(); } m_file->deleteLater(); - m_file = Q_NULLPTR; + m_file = nullptr; QFile::remove(oldFile); } /* Open a new temporary file and append previous data */ @@ -160,46 +160,30 @@ bool File::rename(ResourceItem *resource) ******************************************************************************/ void File::setCreationFileTime(const QDateTime &newDate) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) if (m_file && m_file->isOpen()) { m_file->setFileTime(newDate, QFileDevice::FileBirthTime); } -#else - Q_UNUSED(newDate) -#endif } void File::setLastModifiedFileTime(const QDateTime &newDate) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) if (m_file && m_file->isOpen()) { m_file->setFileTime(newDate, QFileDevice::FileModificationTime); } -#else - Q_UNUSED(newDate) -#endif } void File::setAccessFileTime(const QDateTime &newDate) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) if (m_file && m_file->isOpen()) { m_file->setFileTime(newDate, QFileDevice::FileAccessTime); } -#else - Q_UNUSED(newDate) -#endif } void File::setMetadataChangeFileTime(const QDateTime &newDate) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) if (m_file && m_file->isOpen()) { m_file->setFileTime(newDate, QFileDevice::FileMetadataChangeTime); } -#else - Q_UNUSED(newDate) -#endif } /****************************************************************************** @@ -207,18 +191,13 @@ void File::setMetadataChangeFileTime(const QDateTime &newDate) inline QString File::nextAvailableName(const QString &name) { const QFileInfo fi(name); - - const QString prefix = QString("%0/%1 (") - .arg(fi.absolutePath(), fi.baseName()); - - const QString suffix = QString(").%0") - .arg(fi.completeSuffix()); - - QString newFileName = name; - int i = 0; + auto prefix = QString("%0/%1 (").arg(fi.absolutePath(), fi.baseName()); + auto suffix = QString(").%0").arg(fi.completeSuffix()); + auto newFileName = name; + int increment = 0; do { - newFileName = QString("%0%1%2").arg(prefix, QString::number(i), suffix); - i++; + newFileName = QString("%0%1%2").arg(prefix, QString::number(increment), suffix); + increment++; } while (QFile::exists(newFileName)); return newFileName; } @@ -250,9 +229,9 @@ void File::write(const QByteArray &data) bool File::commit() { if (m_file) { - const bool commited = m_file->commit(); + auto commited = m_file->commit(); m_file->deleteLater(); - m_file = Q_NULLPTR; + m_file = nullptr; return commited; } return false; @@ -268,7 +247,7 @@ void File::cancel() if (m_file) { m_file->cancelWriting(); m_file->deleteLater(); - m_file = Q_NULLPTR; + m_file = nullptr; } } @@ -280,5 +259,5 @@ QString File::customFileName() const QFileInfo fi(m_file->fileName()); return fi.completeBaseName(); } - return QString(); + return {}; } diff --git a/src/core/file.h b/src/core/file.h index e6abb1a7..6a3d2ee7 100644 --- a/src/core/file.h +++ b/src/core/file.h @@ -35,8 +35,8 @@ class File : public QObject Error }; - explicit File(QObject *parent = Q_NULLPTR); - ~File() Q_DECL_OVERRIDE; + explicit File(QObject *parent = nullptr); + ~File() override; static void setFileAccessManager(IFileAccessManager *manager); @@ -56,7 +56,7 @@ class File : public QObject void setMetadataChangeFileTime(const QDateTime &newDate); private: - QSaveFile *m_file = Q_NULLPTR; + QSaveFile *m_file = nullptr; inline OpenFlag open(const QString &fileName); static inline QString nextAvailableName(const QString &name); diff --git a/src/core/fileaccessmanager.h b/src/core/fileaccessmanager.h index 36e3366a..24a2151c 100644 --- a/src/core/fileaccessmanager.h +++ b/src/core/fileaccessmanager.h @@ -27,17 +27,17 @@ class FileAccessManager : public QObject, public IFileAccessManager Q_OBJECT public: - explicit FileAccessManager(QWidget *parent = Q_NULLPTR); - ~FileAccessManager() Q_DECL_OVERRIDE = default; + explicit FileAccessManager(QWidget *parent = nullptr); + ~FileAccessManager() override = default; - Settings* settings() const Q_DECL_OVERRIDE; + Settings* settings() const override; void setSettings(Settings *settings); - ExistingFileOption aboutToModify(const QString &filename) Q_DECL_OVERRIDE; + ExistingFileOption aboutToModify(const QString &filename) override; private: QWidget *m_parent; - Settings *m_settings= Q_NULLPTR; + Settings *m_settings= nullptr; }; #endif // CORE_FILE_ACCESS_MANAGER_H diff --git a/src/core/fileutils.cpp b/src/core/fileutils.cpp index 6b90310b..83d573d3 100644 --- a/src/core/fileutils.cpp +++ b/src/core/fileutils.cpp @@ -16,42 +16,14 @@ #include "fileutils.h" +#include + #include #include -// ******************************************************** -// Inpired by: QtCreator source code -// Utils::FileNameValidatingLineEdit::validateFileName -// ******************************************************** -/* - * Naming a file like a device name will break on Windows, - * even if it is "com1.txt". - * Since we are cross-platform, we generally disallow such file names. - */ -#define WINDOWS_RESERVED_DEVICE_NAMES "CON|PRN|AUX|NUL" \ - "|COM1|COM2|COM3|COM4|COM5|COM6|COM7|COM8|COM9" \ - "|LPT1|LPT2|LPT3|LPT4|LPT5|LPT6|LPT7|LPT8|LPT9" - -/* - * Validate a file base name, check for forbidden characters/strings. - */ -#define PRINTABLE_ASCII_CHARS "<>:\"|?*" -#define SLASHES "/\\" - -static const char s_forbidden_chars_sub_dir[] = PRINTABLE_ASCII_CHARS; -static const char s_forbidden_chars_no_sub_dir[] = PRINTABLE_ASCII_CHARS SLASHES; - -static const char *s_forbidden_sub_strings[] = {".."}; -static const int s_forbidden_sub_strings_count = sizeof(s_forbidden_sub_strings)/sizeof(const char *); -static const QString s_substitute_char('_'); -static const QString s_substitute_file_name("file"); - -/* - * This list of legal characters for filenames is limited to avoid injections - * of special or invisible characters that could be not supported by the OS. - */ -static const QString C_LEGAL_CHARS = QLatin1String("-+' @()[]{}°#,.&"); +const char *S_FORBIDDEN_SUB_STRINGS[] = {".."}; +const int S_FORBIDDEN_SUB_STRINGS_COUNT = sizeof(S_FORBIDDEN_SUB_STRINGS)/sizeof(const char *); /****************************************************************************** @@ -64,22 +36,22 @@ QString FileUtils::validateFileName(const QString &name, bool allowSubDir) QString fixedName; const char *forbiddenChars = allowSubDir - ? s_forbidden_chars_sub_dir - : s_forbidden_chars_no_sub_dir; + ? S_FORBIDDEN_CHARS_SUB_DIR + : S_FORBIDDEN_CHARS_NO_SUB_DIR; // Characters for (auto ch : name) { if (ch < QLatin1Char(32)) { // Non-printable characters // ASCII control characters not allowed on Windows - fixedName += s_substitute_char; + fixedName += S_SUBSTITUTE_CHAR; } else if (ch < QLatin1Char(127)) { // Printable ASCII characters bool passed = true; for (const char *c = forbiddenChars; *c; ++c) { if (ch == QLatin1Char(*c)) { - fixedName += s_substitute_char; + fixedName += S_SUBSTITUTE_CHAR; passed = false; break; } @@ -90,7 +62,7 @@ QString FileUtils::validateFileName(const QString &name, bool allowSubDir) } else if (ch == QLatin1Char(127)) { // DEL char - fixedName += s_substitute_char; + fixedName += S_SUBSTITUTE_CHAR; } else { // allow all other chars in filename fixedName += ch; @@ -98,13 +70,13 @@ QString FileUtils::validateFileName(const QString &name, bool allowSubDir) } // Substrings - for (int s = 0; s < s_forbidden_sub_strings_count; ++s) { - const QLatin1String notAllowedSubString(s_forbidden_sub_strings[s]); - fixedName = fixedName.replace(notAllowedSubString, s_substitute_char); + for (auto s = 0; s < S_FORBIDDEN_SUB_STRINGS_COUNT; ++s) { + const QLatin1StringView notAllowedSubString(S_FORBIDDEN_SUB_STRINGS[s]); + fixedName = fixedName.replace(notAllowedSubString, S_SUBSTITUTE_CHAR); } // Windows devices - QRegularExpression regex( + static QRegularExpression regex( QString("^") // ********************* // captured group #0 @@ -127,13 +99,13 @@ QString FileUtils::validateFileName(const QString &name, bool allowSubDir) if (match.hasMatch()) { QString subdir = allowSubDir ? match.captured("subdir") : QString(); QString extension = match.captured("extension"); - fixedName = subdir + s_substitute_file_name + extension; + fixedName = subdir + S_SUBSTITUTE_FILE_NAME + extension; } // Windows end char rule if ( fixedName.endsWith(QLatin1Char(' ')) || fixedName.endsWith(QLatin1Char('.'))) { - fixedName += s_substitute_char; + fixedName += S_SUBSTITUTE_CHAR; } return fixedName; @@ -148,7 +120,7 @@ QString FileUtils::validateFileName(const QString &name, bool allowSubDir) static QString capitalize(const QString &sentence) { auto capitalized = sentence.toLower(); - for (auto sep: {" ", ",", "-", "_", "\"", "'", "@"}) { + for (auto sep : {" ", ",", "-", "_", "\"", "'", "@"}) { auto words = capitalized.split(sep, Qt::KeepEmptyParts); for (int i = 0; i < words.size(); ++i) { if (words[i].count() > 0) { diff --git a/src/core/format.cpp b/src/core/format.cpp index d8598216..e40c6acb 100644 --- a/src/core/format.cpp +++ b/src/core/format.cpp @@ -16,19 +16,20 @@ #include "format.h" +#include + #include #include #include #include #include -static const QString s_infinite_symbol = QString::fromUtf8("\xE2\x88\x9E"); +using namespace Qt::Literals::StringLiterals; + -/****************************************************************************** - ******************************************************************************/ QString Format::infinity() { - return s_infinite_symbol; + return SYMBOL_INFINITE; } /****************************************************************************** @@ -39,24 +40,24 @@ QString Format::infinity() QString Format::timeToString(QTime time) { if (!time.isValid()) { - return QLatin1String("--:--"); + return "--:--"_L1; } if (time < QTime(0, 0, 1, 0)) { - return time.toString("00:01"); + return time.toString("00:01"_L1); } if (time < QTime(1, 0, 0, 0)) { - return time.toString("mm:ss"); + return time.toString("mm:ss"_L1); } - return time.toString("hh:mm:ss"); + return time.toString("hh:mm:ss"_L1); } QString Format::timeToString(qint64 seconds) { if (seconds < 0) { - return QLatin1String("--:--"); + return "--:--"_L1; } - if (seconds >= 24*60*60) { // More than one day - return s_infinite_symbol; + if (seconds >= ONE_DAY_IN_SECONDS) { // More than one day + return SYMBOL_INFINITE; } QTime time(0, 0, 0, 0); time = time.addSecs(static_cast(seconds)); @@ -70,7 +71,7 @@ QString Format::timeToString(qint64 seconds) */ QString Format::fileSizeToString(qsizetype size) { - if (size < 0 || size >= SIZE_MAX) { + if (size < 0 || size >= PTRDIFF_MAX) { return tr("Unknown"); } if (size == 0) { @@ -107,11 +108,11 @@ QString Format::fileSizeToString(qsizetype size) */ QString Format::fileSizeThousandSeparator(qsizetype size) { - QString number = QString::number(size); - int i = number.count(); + auto number = QString::number(size); + auto i = number.count(); while (i > 3) { i -= 3; - number.insert(i, QLatin1Char(',')); + number.insert(i, ","_L1); } return number; } @@ -132,7 +133,7 @@ QString Format::yesOrNo(bool yes) QString Format::currentSpeedToString(qreal speed, bool showInfiniteSymbol) { if (speed < 0 || !qIsFinite(speed)) { - return showInfiniteSymbol ? s_infinite_symbol : QLatin1String("-"); + return showInfiniteSymbol ? SYMBOL_INFINITE : QLatin1String("-"); } speed /= 1024.0; // KB if (speed < 1000) { @@ -181,48 +182,50 @@ qreal Format::parsePercentDecimal(const QString &text) ******************************************************************************/ qsizetype Format::parseBytes(const QString &text) { - QString textwithoutTilde = text; - textwithoutTilde.remove(QChar('~')); + QString textWithoutTilde = text; + textWithoutTilde.remove('~'_L1); + + QString numberString = textWithoutTilde; - QString numberString = textwithoutTilde; - numberString.remove(QRegularExpression("[a-zA-Z]*")); + static QRegularExpression reLetters("[a-zA-Z]*"); + numberString.remove(reLetters); qreal decimal = 0; if (!parseDouble(numberString, decimal)) { return -1; } - QString unitString = textwithoutTilde; + QString unitString = textWithoutTilde; unitString.remove(numberString); unitString = unitString.toUpper(); qreal multiple = 0; - if ( unitString == QLatin1String("B") || - unitString == QLatin1String("BYTE") || - unitString == QLatin1String("BYTES")) { + if ( unitString == "B"_L1 || + unitString == "BYTE"_L1 || + unitString == "BYTES"_L1) { multiple = 1; - } else if (unitString == QLatin1String("KB")) { + } else if (unitString == "KB"_L1) { multiple = 1000; - } else if (unitString == QLatin1String("MB")) { + } else if (unitString == "MB"_L1) { multiple = 1000000; - } else if (unitString == QLatin1String("GB")) { + } else if (unitString == "GB"_L1) { multiple = 1000000000; - } else if (unitString == QLatin1String("TB")) { + } else if (unitString == "TB"_L1) { multiple = 1000000000000; - } else if (unitString == QLatin1String("KIB")) { + } else if (unitString == "KIB"_L1) { multiple = 1024; // 1 KiB = 2^10 bytes = 1024 bytes - } else if (unitString == QLatin1String("MIB")) { + } else if (unitString == "MIB"_L1) { multiple = 1048576; // 1 MiB = 2^20 bytes = 1048576 bytes - } else if (unitString == QLatin1String("GIB")) { + } else if (unitString == "GIB"_L1) { multiple = 1073741824; // 1 GiB = 2^30 bytes = 1073741824 bytes - } else if (unitString == QLatin1String("TIB")) { + } else if (unitString == "TIB"_L1) { multiple = 1099511627776; // 1 TiB = 2^40 bytes = 1099511627776 bytes } else { @@ -294,7 +297,7 @@ QString Format::wrapText(const QString &text, int blockLength) ******************************************************************************/ QString Format::boolToHtml(bool value) { - return value ? "True" : "False"; + return value ? "True"_L1 : "False"_L1; } QString Format::sizeToHtml(int size) @@ -307,7 +310,7 @@ QString Format::markDownToHtml(const QString &markdown) { /// \todo Replace this with QTextDocument::setMarkDown() introduced in Qt 5.14. QString html = markdown; - html = html.replace('\n', "
        \n"); + html = html.replace("\n"_L1, "
        \n"_L1); return html; } diff --git a/src/core/htmlparser.cpp b/src/core/htmlparser.cpp index 8a0c24b3..ce793b12 100644 --- a/src/core/htmlparser.cpp +++ b/src/core/htmlparser.cpp @@ -30,7 +30,7 @@ static ResourceItem* createResourceItem(const GumboElement &element, const QUrl &baseUrl) { - const GumboVector* attributes = &element.attributes; + auto attributes = &element.attributes; GumboAttribute* href = nullptr; GumboAttribute* alt = nullptr; @@ -66,15 +66,15 @@ static ResourceItem* createResourceItem(const GumboElement &element, const QUrl if (url2.isEmpty()) { return nullptr; } - QUrl url3 = baseUrl.resolved(url2); + auto url3 = baseUrl.resolved(url2); - QString url = url3.toString(); + auto url = url3.toString(); - QString fullfilename = url; + auto fullfilename = url; { if (!fullfilename.isEmpty()) { - const QRegularExpression re{ + static QRegularExpression re{ "^(.*)(" + QRegularExpression::escape("/") + ")$", QRegularExpression::CaseInsensitiveOption}; fullfilename = fullfilename.replace(re, "\\1"); @@ -93,7 +93,7 @@ static ResourceItem* createResourceItem(const GumboElement &element, const QUrl QString titles = title ? QString(title->value) : QString(); QString alts = alt ? QString(alt->value) : QString(); - QString description = !alts.isEmpty() ? alts : titles; + auto description = !alts.isEmpty() ? alts : titles; auto item = new ResourceItem(); item->setUrl(url); @@ -109,9 +109,9 @@ static void searchForLinks(GumboNode* node, Model *model, const QUrl &url) if (node->v.element.tag == GUMBO_TAG_A) { - ResourceItem *item = createResourceItem(node->v.element, url); + auto item = createResourceItem(node->v.element, url); if (item) { - ResourceModel *linkModel = model->linkModel(); + auto linkModel = model->linkModel(); linkModel->add(item); } @@ -128,15 +128,15 @@ static void searchForLinks(GumboNode* node, Model *model, const QUrl &url) /// \todo GUMBO_TAG_AUDIO /// \todo GUMBO_TAG_SOURCE - ResourceItem *item = createResourceItem(node->v.element, url); + auto item = createResourceItem(node->v.element, url); if (item) { - ResourceModel *contentModel = model->contentModel(); + auto contentModel = model->contentModel(); contentModel->add(item); } } - GumboVector* children = &node->v.element.children; - for (unsigned int i = 0; i < children->length; ++i) { + auto children = &node->v.element.children; + for (auto i = 0; i < children->length; ++i) { auto childNode = static_cast(children->data[i]); searchForLinks(childNode, model, url); } @@ -149,7 +149,7 @@ static void searchForLinks(GumboNode* node, Model *model, const QUrl &url) void HtmlParser::parse(const QByteArray &bytes, const QUrl &url, Model *model) { Q_ASSERT(model); - GumboOutput* output = gumbo_parse(bytes.constData()); + auto output = gumbo_parse(bytes.constData()); searchForLinks(output->root, model, url); gumbo_destroy_output(&kGumboDefaultOptions, output); } diff --git a/src/core/locale.cpp b/src/core/locale.cpp index 0f81f8bd..ec21ab92 100644 --- a/src/core/locale.cpp +++ b/src/core/locale.cpp @@ -44,7 +44,7 @@ static void populateLocales() // Get locale from the ISO 639 language code QList locales; - foreach (const QString &dotQM, allDotQMs) { + for (const auto &dotQM : allDotQMs) { auto code = dotQM; code.replace("dza_", ""); code.replace(".qm", ""); @@ -61,29 +61,29 @@ QStringList Locale::availableLanguages() populateLocales(); } QStringList languageNames; - foreach (const QLocale &locale, s_locales) { + for (const auto &locale : s_locales) { languageNames << locale.nativeLanguageName(); } return languageNames; } -QString Locale::toLanguage(int index) +QString Locale::toLanguage(qsizetype index) { if (index >= 0 && index < s_locales.count()) { - const QLocale &locale = s_locales.at(index); + auto locale = s_locales.at(index); return locale.name(); } return QLatin1String(""); // Must be an empty string, not a null QString } -int Locale::fromLanguage(QString language) +qsizetype Locale::fromLanguage(QString language) { if (language.isEmpty()) { language = QLocale::system().name(); } - for (int index = 0; index < s_locales.count(); ++index) { - const QLocale &locale = s_locales.at(index); - QString localeLanguage = locale.name(); + for (auto index = 0; index < s_locales.count(); ++index) { + auto locale = s_locales.at(index); + auto localeLanguage = locale.name(); if (localeLanguage.compare(language, Qt::CaseInsensitive) == 0) { return index; } @@ -100,10 +100,10 @@ void Locale::applyLanguage(const QString &language) delete s_translator; s_translator = nullptr; } - const QLocale locale = !language.isEmpty() ? QLocale(language) : QLocale::system(); - const QString localeName = locale.name(); - const QString localeFilename = translationFileName(localeName); - const QString localeInfo = QObject::tr("translation '%0', locale '%1': %2") + auto locale = !language.isEmpty() ? QLocale(language) : QLocale::system(); + auto localeName = locale.name(); + auto localeFilename = translationFileName(localeName); + auto localeInfo = QObject::tr("translation '%0', locale '%1': %2") .arg(language, localeName, localeFilename); s_translator = new QTranslator(); diff --git a/src/core/locale.h b/src/core/locale.h index 2896d103..a0a6e25c 100644 --- a/src/core/locale.h +++ b/src/core/locale.h @@ -25,8 +25,8 @@ class Locale public: static QStringList availableLanguages(); - static QString toLanguage(int index); - static int fromLanguage(QString language); + static QString toLanguage(qsizetype index); + static qsizetype fromLanguage(QString language); static void applyLanguage(const QString &language); }; diff --git a/src/core/mask.cpp b/src/core/mask.cpp index ce4890ef..314f77c9 100644 --- a/src/core/mask.cpp +++ b/src/core/mask.cpp @@ -16,19 +16,15 @@ #include "mask.h" +#include + #include #include #include #include -static const QString NAME = "*name*"; -static const QString EXT = "*ext*"; -static const QString URL = "*url*"; -static const QString CURL = "*curl*"; -static const QString FLATURL = "*flaturl*"; -static const QString SUBDIRS = "*subdirs*"; -static const QString FLATSUBDIRS = "*flatsubdirs*"; -static const QString QSTRING = "*qstring*"; +using namespace Qt::Literals::StringLiterals; + static const QStringList s_tags { @@ -50,7 +46,7 @@ static QString decodePercentEncoding(const QString &input) * when the URL is misformed and contains a mix * of ASCII and UTF-8 encoding. */ - QString decoded = input; + auto decoded = input; decoded.replace("%0A", "\r"); decoded.replace("%0D", "\n"); decoded.replace("%20", " "); @@ -91,7 +87,7 @@ QString Mask::decodeMagnetEncoding(const QString &s) return ret; } - int high; + int high = 0; if (*i >= '0' && *i <= '9') high = (*i).toLatin1() - '0'; else if (*i >= 'A' && *i <= 'F') high = (*i).toLatin1() + 10 - 'A'; else if (*i >= 'a' && *i <= 'f') high = (*i).toLatin1() + 10 - 'a'; @@ -106,7 +102,7 @@ QString Mask::decodeMagnetEncoding(const QString &s) return ret; } - int low; + int low = 0; if(*i >= '0' && *i <= '9') low = (*i).toLatin1() - '0'; else if(*i >= 'A' && *i <= 'F') low = (*i).toLatin1() + 10 - 'A'; else if(*i >= 'a' && *i <= 'f') low = (*i).toLatin1() + 10 - 'a'; @@ -126,9 +122,9 @@ QString Mask::decodeMagnetEncoding(const QString &s) ******************************************************************************/ QUrl Mask::fromUserInput(const QString &input) { - QString cleaned = decodePercentEncoding(input); + auto cleaned = decodePercentEncoding(input); cleaned = cleaned.trimmed(); - QUrl url = QUrl::fromUserInput(cleaned); + auto url = QUrl::fromUserInput(cleaned); if (url.isEmpty()) { url = QUrl::toPercentEncoding(cleaned); } @@ -147,14 +143,14 @@ QUrl Mask::fromUserInput(const QString &input) * - Not a fragment: myfile#.txt */ if (url.hasQuery()) { - const QString query = url.query(); + auto query = url.query(); if ( query.isEmpty() || query.contains('=') || query.contains('#') || url.hasFragment()) { // valid query, just continue. } else { - QString encoded = cleaned; + auto encoded = cleaned; encoded.replace("?", "%3F"); encoded.replace("#", "%23"); url = QUrl::fromUserInput(encoded); @@ -164,7 +160,7 @@ QUrl Mask::fromUserInput(const QString &input) } } else { if (url.hasFragment()) { - QString encoded = cleaned; + auto encoded = cleaned; encoded.replace("?", "%3F"); encoded.replace("#", "%23"); url = QUrl::fromUserInput(encoded); @@ -176,42 +172,38 @@ QUrl Mask::fromUserInput(const QString &input) return url; } -QString Mask::interpret(const QString &input, - const QString &customFileName, - const QString &mask) +QString Mask::interpret(const QString &input, const QString &customFileName, const QString &mask) { - const QUrl url = fromUserInput(input); + auto url = fromUserInput(input); return interpret(url, customFileName, mask); } -QString Mask::interpret(const QUrl &url, - const QString &customFileName, - const QString &mask) +QString Mask::interpret(const QUrl &url, const QString &customFileName, const QString &mask) { if (!url.isValid()) { - return QString(); + return {}; } - QString decodedMask = QString("%0.%1").arg(NAME, EXT); - if (mask.isNull() || mask.isEmpty()) { + auto decodedMask = QString("%0.%1").arg(NAME, EXT); + if (mask.isEmpty()) { decodedMask = QString("%0/%1/%2.%3").arg(URL, SUBDIRS, NAME, EXT); } else { decodedMask = mask; } - const QString host = url.host(); - const QString path = url.path(); - const QString filename = url.fileName(); - const QString query = url.query(); + auto host = url.host(); + auto path = url.path(); + auto filename = url.fileName(); + auto query = url.query(); QFileInfo fi(filename); - QString basename = fi.completeBaseName(); - QString suffix = fi.suffix(); + auto basename = fi.completeBaseName(); + auto suffix = fi.suffix(); if (!customFileName.isEmpty()) { basename = customFileName; } - QString subdirs = path; + auto subdirs = path; subdirs.chop(filename.count()); if (subdirs.startsWith(QChar('/'))) { subdirs.remove(0, 1); @@ -220,12 +212,12 @@ QString Mask::interpret(const QUrl &url, subdirs.chop(1); } - QString fullUrl = host + path; + auto fullUrl = host + path; - QString flatUrl = fullUrl; + auto flatUrl = fullUrl; flatUrl.replace(QChar('/'), QChar('-')); - QString flatSubdirs = subdirs; + auto flatSubdirs = subdirs; flatSubdirs.replace(QChar('/'), QChar('-')); // Renaming Tags @@ -269,15 +261,15 @@ QStringList Mask::tags() */ QString Mask::description(const QString &tag) { - if (tag == NAME ) return tr("File name"); - if (tag == EXT ) return tr("Extension"); - if (tag == URL ) return tr("Base URL"); - if (tag == CURL ) return tr("Full URL"); - if (tag == FLATURL ) return tr("Flat full URL"); - if (tag == SUBDIRS ) return tr("URL subdirectories"); - if (tag == FLATSUBDIRS ) return tr("Flat URL subdirectories"); - if (tag == QSTRING ) return tr("Query string"); - return QString(); + if (tag == NAME ) {return tr("File name");} + if (tag == EXT ) {return tr("Extension");} + if (tag == URL ) {return tr("Base URL");} + if (tag == CURL ) {return tr("Full URL");} + if (tag == FLATURL ) {return tr("Flat full URL");} + if (tag == SUBDIRS ) {return tr("URL subdirectories");} + if (tag == FLATSUBDIRS ) {return tr("Flat URL subdirectories");} + if (tag == QSTRING ) {return tr("Query string");} + return {}; } /****************************************************************************** diff --git a/src/core/mask.h b/src/core/mask.h index 832335b5..0e74a673 100644 --- a/src/core/mask.h +++ b/src/core/mask.h @@ -28,13 +28,8 @@ class Mask : public QObject public: static QUrl fromUserInput(const QString &input); - static QString interpret(const QString &input, - const QString &customFileName, - const QString &mask); - - static QString interpret(const QUrl &url, - const QString &customFileName, - const QString &mask); + static QString interpret(const QString &input, const QString &customFileName, const QString &mask); + static QString interpret(const QUrl &url, const QString &customFileName, const QString &mask); static QStringList tags(); static QString description(const QString &tag); diff --git a/src/core/mimedatabase.cpp b/src/core/mimedatabase.cpp index 622b7c08..8b16005f 100644 --- a/src/core/mimedatabase.cpp +++ b/src/core/mimedatabase.cpp @@ -16,6 +16,8 @@ #include "mimedatabase.h" +#include + #include #include #include @@ -77,7 +79,7 @@ void MimeDatabaseSingleton::init() * Construction of QFileIconProvider is heavy */ m_fileIconProvider.setOptions(QFileIconProvider::DontUseCustomDirectoryIcons); - m_defaultPixmap = fileIcon(QUrl("page.html"), default_icon_size); + m_defaultPixmap = fileIcon(QUrl("page.html"), DEFAULT_ICON_SIZE); } /****************************************************************************** @@ -95,7 +97,7 @@ QPixmap MimeDatabaseSingleton::fileIcon(const QUrl &url, int extend) if ( fileInfo.suffix().isEmpty() || (fileInfo.suffix() == "exe" && fileInfo.exists())) { - QIcon icon = m_fileIconProvider.icon(fileInfo); + auto icon = m_fileIconProvider.icon(fileInfo); pixmap = icon.pixmap(extend); if (pixmap.isNull()) { pixmap = m_defaultPixmap; @@ -103,28 +105,28 @@ QPixmap MimeDatabaseSingleton::fileIcon(const QUrl &url, int extend) return pixmap; } - const QString key = QString("%0 %1").arg(fileInfo.suffix(), QString::number(extend)); + auto key = QString("%0 %1").arg(fileInfo.suffix(), QString::number(extend)); if (!QPixmapCache::find(key, &pixmap)) { - const QString nativeName = url.fileName(); + auto nativeName = url.fileName(); Q_ASSERT(!nativeName.contains('\\')); Q_ASSERT(!nativeName.contains('/')); // otherwise the temporary file is not opened const QDir dir(QDir::tempPath()); if (!dir.exists()) { qWarning("Can't find: '%s'.", dir.path().toLatin1().data()); - return QPixmap(); + return {}; } - const QString filename = dir.filePath("XXXXXX_" + nativeName); + auto filename = dir.filePath("XXXXXX_" + nativeName); QTemporaryFile tempFile(filename); if (tempFile.open()) { /* This is a trick to write the file */ } const QFileInfo tempFileInfo(tempFile); - QIcon icon = m_fileIconProvider.icon(tempFileInfo); + auto icon = m_fileIconProvider.icon(tempFileInfo); if (icon.isNull()) { icon = m_fileIconProvider.icon(QFileIconProvider::File); } diff --git a/src/core/mimedatabase.h b/src/core/mimedatabase.h index bda4514c..6173d7c6 100644 --- a/src/core/mimedatabase.h +++ b/src/core/mimedatabase.h @@ -17,13 +17,13 @@ #ifndef CORE_MIME_DATABASE_H #define CORE_MIME_DATABASE_H +#include #include #include +#include #include -constexpr int default_icon_size = 32; - /*! * \class MimeDatabase @@ -32,7 +32,7 @@ constexpr int default_icon_size = 32; class MimeDatabase { public: - static QPixmap fileIcon(const QUrl &url, int extend = default_icon_size); + static QPixmap fileIcon(const QUrl &url, int extend = DEFAULT_ICON_SIZE); }; diff --git a/src/core/model.h b/src/core/model.h index 796493c7..5427d657 100644 --- a/src/core/model.h +++ b/src/core/model.h @@ -31,7 +31,7 @@ class Model : public QObject enum Tab{LINK, CONTENT}; explicit Model(QObject *parent); - ~Model() Q_DECL_OVERRIDE = default; + ~Model() override = default; ResourceModel* currentModel() const; diff --git a/src/core/networkmanager.cpp b/src/core/networkmanager.cpp index da18427c..763c22a1 100644 --- a/src/core/networkmanager.cpp +++ b/src/core/networkmanager.cpp @@ -16,6 +16,7 @@ #include "networkmanager.h" +#include #include #include @@ -24,12 +25,10 @@ #include #include -constexpr int max_redirects_allowed = 5; NetworkManager::NetworkManager(QObject *parent) : QObject(parent) , m_networkAccessManager(new QNetworkAccessManager(this)) - , m_settings(Q_NULLPTR) { } @@ -114,30 +113,22 @@ QNetworkReply* NetworkManager::get(const QUrl &url, const QString &referer) request.setUrl(url); // User-Agent - const QString httpUserAgent = m_settings ? m_settings->httpUserAgent() : QLatin1String(""); + auto httpUserAgent = m_settings ? m_settings->httpUserAgent() : QLatin1String(""); request.setHeader(QNetworkRequest::UserAgentHeader, httpUserAgent); // Referer if (!referer.isEmpty()) { - QByteArray rawReferer = referer.toUtf8(); + auto rawReferer = referer.toUtf8(); request.setRawHeader(QByteArray("Referer"), rawReferer); } // SSL request.setSslConfiguration(QSslConfiguration::defaultConfiguration()); // HTTPS + request.setMaximumRedirectsAllowed(MAX_REDIRECTS_ALLOWED); + request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); + + auto reply = m_networkAccessManager->get(request); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) - request.setMaximumRedirectsAllowed(max_redirects_allowed); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, - QNetworkRequest::NoLessSafeRedirectPolicy); -#endif - - QNetworkReply* reply = m_networkAccessManager->get(request); Q_ASSERT(reply); connect(reply, SIGNAL(metaDataChanged()), this, SLOT(onMetaDataChanged())); connect(reply, SIGNAL(redirected(QUrl)), this, SLOT(onRedirected(QUrl))); diff --git a/src/core/networkmanager.h b/src/core/networkmanager.h index 409f5700..41fda681 100644 --- a/src/core/networkmanager.h +++ b/src/core/networkmanager.h @@ -31,12 +31,12 @@ class NetworkManager : public QObject public: explicit NetworkManager(QObject *parent); - ~NetworkManager() Q_DECL_OVERRIDE = default; + ~NetworkManager() override = default; Settings* settings() const; void setSettings(Settings *settings); - QNetworkReply* get(const QUrl &url, const QString &referer = QString()); + QNetworkReply* get(const QUrl &url, const QString &referer = {}); static QStringList proxyTypeNames(); @@ -47,8 +47,8 @@ private slots: private: /* Network parameters (SSL, Proxy, UserAgent...) */ - QNetworkAccessManager *m_networkAccessManager; - Settings *m_settings; + QNetworkAccessManager *m_networkAccessManager = nullptr; + Settings *m_settings = nullptr; void setNetworkSettings(Settings *settings); }; diff --git a/src/core/regex.cpp b/src/core/regex.cpp index 188e2438..b507e84b 100644 --- a/src/core/regex.cpp +++ b/src/core/regex.cpp @@ -19,25 +19,22 @@ #include #include - -static const QRegularExpression reBatch("([\\[\\(]\\d+[:\\-\\s]\\d+[\\]\\)])"); -static const QRegularExpression reGroup("[\\[\\(](\\d+)[:\\-\\s](\\d+)[\\]\\)]"); - constexpr int firstGroupPosition = 1; // 0 is reseved to full string constexpr int secondGroupPosition = 2; struct Capture { - QString capture; - int pos{0}; - int len{0}; + QString capture = {}; + qsizetype pos = 0; + qsizetype len = 0; QStringList interpretedCapture; }; static QList capture(const QString &str) { QList captures; + static QRegularExpression reBatch("([\\[\\(]\\d+[:\\-\\s]\\d+[\\]\\)])"); QRegularExpressionMatchIterator i = reBatch.globalMatch(str); while (i.hasNext()) { QRegularExpressionMatch match = i.next(); @@ -88,9 +85,9 @@ QStringList Regex::interpret(const QString &str) * "[8:11]" is interpreted {8 9 10 11} * */ - for (int index = 0; index < captures.count(); ++index) { + for (auto index = 0; index < captures.count(); ++index) { Capture &cap = captures[index]; - + static QRegularExpression reGroup("[\\[\\(](\\d+)[:\\-\\s](\\d+)[\\]\\)]"); QRegularExpressionMatch match = reGroup.match(cap.capture); if (!match.hasMatch()) { Q_ASSERT(false); @@ -99,18 +96,18 @@ QStringList Regex::interpret(const QString &str) auto strBegin = match.captured(firstGroupPosition); auto strEnd = match.captured(secondGroupPosition); - int fieldWidth = strBegin.length(); - int begin = strBegin.toInt(); - int end = strEnd.toInt(); + auto fieldWidth = strBegin.length(); + auto begin = strBegin.toInt(); + auto end = strEnd.toInt(); if (begin > end) { - int t = end; + auto t = end; end = begin; begin = t; fieldWidth = match.captured(secondGroupPosition).length(); } - for (int i = begin; i <= end; ++i) { + for (auto i = begin; i <= end; ++i) { cap.interpretedCapture.append(QString("%0").arg(i, fieldWidth, 10, QChar('0'))); } } @@ -121,11 +118,11 @@ QStringList Regex::interpret(const QString &str) */ QStringList list; list << str; - for (int i = captures.count() - 1; i >= 0; --i) { + for (auto i = captures.count() - 1; i >= 0; --i) { auto capture = captures.at(i); QStringList buffer; - foreach (auto interpretedCapture, capture.interpretedCapture) { - foreach (auto interpreted, list) { + for (auto interpretedCapture : capture.interpretedCapture) { + for (auto interpreted : list) { interpreted.replace(capture.pos, capture.len, interpretedCapture); buffer << interpreted; } @@ -140,7 +137,7 @@ QStringList Regex::getCaptures(const QString &str) { QList captures = capture(str); QStringList ret; - foreach (auto capture, captures) { + for (auto capture : captures) { ret.append(capture.capture); } return ret; diff --git a/src/core/resourceitem.cpp b/src/core/resourceitem.cpp index 8ddfa20a..73643f08 100644 --- a/src/core/resourceitem.cpp +++ b/src/core/resourceitem.cpp @@ -16,6 +16,8 @@ #include "resourceitem.h" +#include + #include #include #include @@ -25,29 +27,7 @@ #include #include -static const QString s_regular = QLatin1String("regular"); -static const QString s_stream = QLatin1String("stream"); -static const QString s_torrent = QLatin1String("torrent"); - - -ResourceItem::ResourceItem() - : m_type(Type::Regular) - , m_url(QString()) - , m_destination(QString()) - , m_mask(QString()) - , m_customFileName(QString()) - , m_referringPage(QString()) - , m_description(QString()) - , m_checkSum(QString()) - , m_streamFileName(QString()) - , m_streamFormatId(QString()) - , m_streamFileSize(0) - , m_torrentPreferredFilePriorities(QString()) -{ -} -/****************************************************************************** - ******************************************************************************/ ResourceItem::Type ResourceItem::type() const { return m_type; @@ -61,17 +41,17 @@ void ResourceItem::setType(Type type) QString ResourceItem::toString(Type type) { switch (type) { - case Type::Stream: return s_stream; - case Type::Torrent: return s_torrent; + case Type::Stream: return S_KEY_STREAM; + case Type::Torrent: return S_KEY_TORRENT; default: - return s_regular; + return S_KEY_REGULAR; } } ResourceItem::Type ResourceItem::fromString(const QString &str) { - if (str.toLower() == s_stream) return Type::Stream; - if (str.toLower() == s_torrent) return Type::Torrent; + if (str.toLower() == S_KEY_STREAM) { return Type::Stream; } + if (str.toLower() == S_KEY_TORRENT) { return Type::Torrent; } return Type::Regular; } @@ -82,6 +62,11 @@ QString ResourceItem::url() const return m_url; } +QUrl ResourceItem::url_TODO() const +{ + return QUrl(m_url); +} + void ResourceItem::setUrl(const QString &url) { m_url = url; @@ -132,17 +117,17 @@ void ResourceItem::setCustomFileName(const QString &customFileName) ******************************************************************************/ QUrl ResourceItem::localFileUrl() const { - const QString path = localFilePath(m_customFileName); + auto path = localFilePath(m_customFileName); return QUrl::fromLocalFile(path); } QString ResourceItem::fileName() const { - const QUrl url = localFileUrl(); + auto url = localFileUrl(); if (!url.isEmpty() && url.isValid()) { return url.fileName(); } - return QString(); + return {}; } QString ResourceItem::localFileFullPath(const QString &customFileName) const @@ -280,16 +265,16 @@ inline QString ResourceItem::localFilePath(const QString &customFileName) const inline QString ResourceItem::localStreamFile(const QString &customFileName) const { - QString url = QUrl(m_url).host() + "/" + m_streamFileName; - QString fileName = Mask::interpret(url, customFileName, m_mask); + QString url = QUrl(m_url).host() % "/" % m_streamFileName; + auto fileName = Mask::interpret(url, customFileName, m_mask); fileName = FileUtils::validateFileName(fileName, true); return QDir(m_destination).filePath(fileName); } inline QString ResourceItem::localMagnetFile(const QString &customFileName) const { - QString displayName = parseMagnetUrl(m_url); - QString fileName = customFileName.isEmpty() ? displayName : customFileName; + auto displayName = parseMagnetUrl(m_url); + auto fileName = customFileName.isEmpty() ? displayName : customFileName; fileName += ".torrent"; // Remark: No mask for magnets @@ -302,21 +287,22 @@ inline QString ResourceItem::localMagnetFile(const QString &customFileName) cons inline QString ResourceItem::parseMagnetUrl(const QString &url) const { /// todo move to Mask::interpretMagnet ? - QRegularExpression regex("^" - + QRegularExpression::escape("magnet:?") - + ".*"+ QRegularExpression::escape("&") + "?" - + QRegularExpression::escape("dn=") - // ********************* - // captured group #1 - // rem: [^A] means anything not A - + "([^" + QRegularExpression::escape("&") + "]*)" - // ********************* - + "(" + QRegularExpression::escape("&") + ".*)?" - + "$" - ); - QRegularExpressionMatch match = regex.match(url); + static QRegularExpression regex( + "^" + % QRegularExpression::escape("magnet:?") + % ".*"% QRegularExpression::escape("&") % "?" + % QRegularExpression::escape("dn=") + // ********************* + // captured group #1 + // rem: [^A] means anything not A + % "([^" % QRegularExpression::escape("&") % "]*)" + // ********************* + % "(" % QRegularExpression::escape("&") % ".*)?" + % "$"); + + auto match = regex.match(url); if (match.hasMatch()) { - QString displayName = match.captured(1); + auto displayName = match.captured(1); displayName = Mask::decodeMagnetEncoding(displayName); return displayName; } @@ -328,7 +314,7 @@ inline QString ResourceItem::parseMagnetUrl(const QString &url) const inline QString ResourceItem::localFile(const QString &destination, const QUrl &url, const QString &customFileName, const QString &mask) { - QString fileName = Mask::interpret(url, customFileName, mask); + auto fileName = Mask::interpret(url, customFileName, mask); fileName = FileUtils::validateFileName(fileName, true); return QDir(destination).filePath(fileName); } diff --git a/src/core/resourceitem.h b/src/core/resourceitem.h index b8f7cb28..a7de00f3 100644 --- a/src/core/resourceitem.h +++ b/src/core/resourceitem.h @@ -24,17 +24,17 @@ #include class ResourceItem -{ +{ public: - ResourceItem(); - ~ResourceItem() = default; - enum class Type { Regular = 0, ///< The resource is a regular file Stream = 1, ///< The resource is a stream Torrent = 2 ///< The resource is a torrent }; + ResourceItem() = default; + ~ResourceItem() = default; + Type type() const; void setType(Type type); @@ -43,6 +43,7 @@ class ResourceItem /* Source */ QString url() const; + QUrl url_TODO() const; void setUrl(const QString &url); QUrl distantFileUrl() const; @@ -59,7 +60,7 @@ class ResourceItem /* Local file URL, once the file is downloaded */ QUrl localFileUrl() const; QString fileName() const; - QString localFileFullPath(const QString &customFileName = QString()) const; + QString localFileFullPath(const QString &customFileName = {}) const; /* Options */ QString referringPage() const; @@ -87,27 +88,27 @@ class ResourceItem void setTorrentPreferredFilePriorities(const QString &priorities); private: - Type m_type{Type::Regular}; - QString m_url; // QUrl ? - QString m_destination; // QDir ? - QString m_mask; // Mask ? - QString m_customFileName; // QFileInfo ? + Type m_type = Type::Regular; + QString m_url = {}; // QUrl ? + QString m_destination = {}; // QDir ? + QString m_mask = {}; // Mask ? + QString m_customFileName = {}; // QFileInfo ? - QString m_referringPage; - QString m_description; + QString m_referringPage = {}; + QString m_description = {}; /* Regular file-specific properties */ - QString m_checkSum; + QString m_checkSum = {}; /* Stream-specific properties */ - QString m_streamFileName; - QString m_streamFormatId; - qsizetype m_streamFileSize{0}; + QString m_streamFileName = {}; + QString m_streamFormatId = {}; + qsizetype m_streamFileSize = 0; - StreamObject::Config m_streamConfig; + StreamObject::Config m_streamConfig = {}; /* Torrent-specific properties */ - QString m_torrentPreferredFilePriorities; + QString m_torrentPreferredFilePriorities = {}; inline QString localFilePath(const QString &customFileName) const; inline QString localStreamFile(const QString &customFileName) const; @@ -115,8 +116,7 @@ class ResourceItem inline QString parseMagnetUrl(const QString &url) const; - inline static QString localFile(const QString &destination, const QUrl &url, - const QString &customFileName, const QString &mask); + inline static QString localFile(const QString &destination, const QUrl &url, const QString &customFileName, const QString &mask); }; #endif // CORE_RESOURCE_ITEM_H diff --git a/src/core/resourcemodel.cpp b/src/core/resourcemodel.cpp index a3f71c60..59162aba 100644 --- a/src/core/resourcemodel.cpp +++ b/src/core/resourcemodel.cpp @@ -20,11 +20,11 @@ #include +using namespace Qt::Literals::StringLiterals; ResourceModel::ResourceModel(QObject *parent) : CheckableTableModel(parent) { - connect(this, SIGNAL(checkStateChanged(QModelIndex , bool)), - this, SLOT(onCheckStateChanged(QModelIndex , bool))); + connect(this, SIGNAL(checkStateChanged(QModelIndex,bool)), this, SLOT(onCheckStateChanged(QModelIndex,bool))); connect(this, SIGNAL(resourceChanged()), this, SLOT(onResourceChanged())); retranslateUi(); @@ -50,7 +50,7 @@ QList ResourceModel::items() const void ResourceModel::add(ResourceItem *item) { - foreach (auto itemOld, m_items) { + for (auto itemOld : m_items) { if (itemOld->url() == item->url()) { return; } @@ -64,7 +64,7 @@ void ResourceModel::add(ResourceItem *item) QList ResourceModel::selection() const { QList selection; - foreach (int row, this->checkedRows()) { + for (auto row : this->checkedRows()) { if (row >= 0 && row < m_items.count()) { selection << m_items.at(row); } @@ -76,7 +76,7 @@ QList ResourceModel::selection() const ******************************************************************************/ void ResourceModel::setDestination(const QString &destination) { - foreach (auto item, m_items) { + for (auto item : m_items) { item->setDestination(destination); } emit resourceChanged(); @@ -84,7 +84,7 @@ void ResourceModel::setDestination(const QString &destination) void ResourceModel::setMask(const QString &mask) { - foreach (auto item, m_items) { + for (auto item : m_items) { item->setMask(mask); } emit resourceChanged(); @@ -127,7 +127,7 @@ void ResourceModel::onResourceChanged() void ResourceModel::retranslateUi() { m_headers = QStringList() - << QString() // checkbox + << ""_L1 // checkbox << tr("Download") << tr("Resource Name") << tr("Description") @@ -138,7 +138,7 @@ void ResourceModel::retranslateUi() ******************************************************************************/ int ResourceModel::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_headers.count(); + return parent.isValid() ? 0 : static_cast(m_headers.count()); } QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -147,25 +147,25 @@ QVariant ResourceModel::headerData(int section, Qt::Orientation orientation, int if (section >= 0 && section < m_headers.count()) { return m_headers.at(section); } - return QVariant(); + return {}; } return QAbstractItemModel::headerData(section, orientation, role); } int ResourceModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_items.count(); + return parent.isValid() ? 0 : static_cast(m_items.count()); } QVariant ResourceModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } ResourceItem *item = m_items.at(index.row()); if (role == Qt::DisplayRole) { switch ( index.column()) { - case 0: return QVariant(); + case 0: return {}; case 1: return item->url(); case 2: return item->customFileName(); case 3: return item->description(); diff --git a/src/core/resourcemodel.h b/src/core/resourcemodel.h index ea55d6e0..53e5cbf7 100644 --- a/src/core/resourcemodel.h +++ b/src/core/resourcemodel.h @@ -27,19 +27,19 @@ class ResourceModel : public CheckableTableModel public: explicit ResourceModel(QObject *parent); - ~ResourceModel() Q_DECL_OVERRIDE = default; + ~ResourceModel() override = default; - void clear() Q_DECL_OVERRIDE; + void clear() override; QList items() const; void add(ResourceItem *item); QList selection() const; - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; void retranslateUi(); diff --git a/src/core/session.cpp b/src/core/session.cpp index 1f5ec0fb..94778100 100644 --- a/src/core/session.cpp +++ b/src/core/session.cpp @@ -231,7 +231,7 @@ static inline void writeJob(const DownloadItem *item, QJsonObject &json) static inline void readList(QList &downloadItems, const QJsonObject &json, DownloadManager *downloadManager) { QJsonArray jobs = json["jobs"].toArray(); - foreach (auto job, jobs) { + for (auto job : jobs) { QJsonObject jobObject = job.toObject(); auto item = readJob(jobObject, downloadManager); downloadItems.append(item); @@ -241,7 +241,7 @@ static inline void readList(QList &downloadItems, const QJsonObj static inline void writeList(const QList &downloadItems, QJsonObject &json) { QJsonArray jobs; - foreach (auto item, downloadItems) { + for (auto item : downloadItems) { QJsonObject jobObject; writeJob(item, jobObject); jobs.append(jobObject); diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 2b5943c1..db2e0f7b 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -16,83 +16,14 @@ #include "settings.h" -#include +#include #include #include #include #include -/*! - * Registry Keys. They must be unique - */ -// Tab General -static const QString REGISTRY_EXISTING_FILE = "ExistingFile"; - -// Tab Interface -static const QString REGISTRY_UI_LANGUAGE = "Language"; -static const QString REGISTRY_UI_THEME = "Theme"; -static const QString REGISTRY_DONT_SHOW_TUTO = "DontShowTutorial"; -static const QString REGISTRY_SHOW_SYSTEM_TRAY = "SystemTrayIconEnabled"; -static const QString REGISTRY_HIDE_MINIMIZED = "HideWhenMinimized"; -static const QString REGISTRY_SHOW_BALLOON = "SystemTrayBalloonEnabled"; -static const QString REGISTRY_MINIMIZE_ESCAPE = "MinimizeWhenEscapePressed"; -static const QString REGISTRY_CONFIRM_REMOVAL = "ConfirmRemoval"; -static const QString REGISTRY_CONFIRM_BATCH = "ConfirmBatchDownload"; -static const QString REGISTRY_PROXY_TYPE = "ProxyType"; -static const QString REGISTRY_PROXY_HOSTNAME = "ProxyHostName"; -static const QString REGISTRY_PROXY_PORT = "ProxyPort"; -static const QString REGISTRY_PROXY_IS_AUTH = "ProxyAuth"; -static const QString REGISTRY_PROXY_USERNAME = "ProxyUser"; -static const QString REGISTRY_PROXY_PASSWORD = "ProxyPwd"; -static const QString REGISTRY_SOCKET_TYPE = "SocketType"; -static const QString REGISTRY_SOCKET_TIMEOUT = "SocketTimeout"; -static const QString REGISTRY_REMOTE_CREATION = "RemoteCreationTime"; -static const QString REGISTRY_REMOTE_LAST_MOD = "RemoteLastModifiedTime"; -static const QString REGISTRY_REMOTE_ACCESS = "RemoteAccessTime"; -static const QString REGISTRY_REMOTE_META_MOD = "RemoteMetadataChangeTime"; -static const QString REGISTRY_STREAM_WATCHED = "StreamMarkWatchedEnabled"; -static const QString REGISTRY_STREAM_SUBTITLE = "StreamSubtitleEnabled"; -static const QString REGISTRY_STREAM_THUMBNAIL = "StreamThumbnailEnabled"; -static const QString REGISTRY_STREAM_DESCR = "StreamDescriptionEnabled"; -static const QString REGISTRY_STREAM_METADATA = "StreamMetaDataEnabled"; -static const QString REGISTRY_STREAM_COMMENT = "StreamCommentEnabled"; -static const QString REGISTRY_STREAM_SHORTCUT = "StreamShortcutEnabled"; - -// Tab Network -static const QString REGISTRY_MAX_SIMULTANEOUS = "MaxSimultaneous"; -static const QString REGISTRY_CONCURRENT_FRAG = "ConcurrentFragments"; -static const QString REGISTRY_CUSTOM_BATCH = "CustomBatchEnabled"; -static const QString REGISTRY_CUSTOM_BATCH_BL = "CustomBatchButtonLabel"; -static const QString REGISTRY_CUSTOM_BATCH_RGE = "CustomBatchRange"; -static const QString REGISTRY_STREAM_HOST = "StreamHostEnabled"; -static const QString REGISTRY_STREAM_HOST_LIST = "StreamHosts"; - -// Tab Privacy -static const QString REGISTRY_REMOVE_COMPLETED = "PrivacyRemoveCompleted"; -static const QString REGISTRY_REMOVE_CANCELED = "PrivacyRemoveCanceled"; -static const QString REGISTRY_REMOVE_PAUSED = "PrivacyRemovePaused"; -static const QString REGISTRY_DATABASE = "Database"; -static const QString REGISTRY_HTTP_USER_AGENT = "HttpUserAgent"; -static const QString REGISTRY_HTTP_REFERRER_ON = "HttpReferringPageEnabled"; -static const QString REGISTRY_HTTP_REFERRER = "HttpReferringPage"; - -// Tab Filters -static const QString REGISTRY_FILTER_KEY = "FilterKey"; -static const QString REGISTRY_FILTER_NAME = "FilterName"; -static const QString REGISTRY_FILTER_VALUE = "FilterValue"; - -// Tab Torrent -static const QString REGISTRY_TORRENT_ENABLED = "TorrentEnabled"; -static const QString REGISTRY_TORRENT_SHARED = "TorrentShareFolderEnabled"; -static const QString REGISTRY_TORRENT_DIR = "TorrentShareFolder"; -static const QString REGISTRY_TORRENT_PEERS = "TorrentPeerList"; -static const QString REGISTRY_TORRENT_ADVANCED = "TorrentAdvanced"; - - -// Tab Advanced -static const QString REGISTRY_CHECK_UPDATE = "CheckUpdate"; - +using namespace Qt::Literals::StringLiterals; static const QLatin1Char STREAM_HOST_SEPARATOR = QLatin1Char(' '); static const QList DEFAULT_STREAM_HOST_LIST = @@ -160,9 +91,7 @@ Settings::Settings(QObject *parent) : AbstractSettings(parent) addDefaultSettingBool(REGISTRY_REMOVE_COMPLETED, false); addDefaultSettingBool(REGISTRY_REMOVE_CANCELED, false); addDefaultSettingBool(REGISTRY_REMOVE_PAUSED, false); - addDefaultSettingString( - REGISTRY_DATABASE, - QString("%0/queue.json").arg(qApp->applicationDirPath())); + addDefaultSettingString(REGISTRY_DATABASE, QString("%0/queue.json").arg(qApp->applicationDirPath())); addDefaultSettingString(REGISTRY_HTTP_USER_AGENT, httpUserAgents().at(0)); addDefaultSettingBool(REGISTRY_HTTP_REFERRER_ON, false); addDefaultSettingString(REGISTRY_HTTP_REFERRER, QLatin1String("https://www.example.com/")); @@ -217,8 +146,7 @@ Settings::Settings(QObject *parent) : AbstractSettings(parent) addDefaultSettingString(REGISTRY_TORRENT_ADVANCED, QLatin1String("")); // Tab Advanced - addDefaultSettingInt(REGISTRY_CHECK_UPDATE, - static_cast(CheckUpdateBeatMode::OnceADay)); + addDefaultSettingInt(REGISTRY_CHECK_UPDATE, static_cast(CheckUpdateBeatMode::OnceADay)); } @@ -702,7 +630,7 @@ void Settings::setFilters(const QList &filters) QStringList keys; QStringList names; QStringList values; - foreach (auto filter, filters) { + for (auto filter : filters) { keys.append(filter.key()); names.append(filter.name()); values.append(filter.regex()); @@ -721,15 +649,15 @@ QList Settings::defaultFilters(bool defaults) if (defaults) { beginRestoreDefault(); } - QStringList keys = getSettingStringList(REGISTRY_FILTER_KEY); - QStringList names = getSettingStringList(REGISTRY_FILTER_NAME); - QStringList values = getSettingStringList(REGISTRY_FILTER_VALUE); + auto keys = getSettingStringList(REGISTRY_FILTER_KEY); + auto names = getSettingStringList(REGISTRY_FILTER_NAME); + auto values = getSettingStringList(REGISTRY_FILTER_VALUE); if (defaults) { endRestoreDefault(); } - const int count = qMin(qMin(keys.count(), values.count()), names.count()); - for (int i = 0; i < count; ++i) { + auto count = qMin(qMin(keys.count(), values.count()), names.count()); + for (auto i = 0; i < count; ++i) { Filter filter; filter.setKey(keys.at(i)); filter.setName(names.at(i)); @@ -744,15 +672,15 @@ QList Settings::defaultFilters(bool defaults) QString Settings::translateFilter(const QString &key, const QString &defaultName) { if (!key.isEmpty()) { - if (key == QLatin1String("KEY_ALL") ) return tr("All Files"); - if (key == QLatin1String("KEY_ARCHIVES") ) return tr("Archives (zip, rar...)"); - if (key == QLatin1String("KEY_APPLICATIONS")) return tr("Application (exe, xpi...)"); - if (key == QLatin1String("KEY_AUDIO") ) return tr("Audio (mp3, wav...)"); - if (key == QLatin1String("KEY_DOCUMENTS") ) return tr("Documents (pdf, odf...)"); - if (key == QLatin1String("KEY_IMAGES") ) return tr("Images (jpg, png...)"); - if (key == QLatin1String("KEY_IMAGES_JPEG") ) return tr("Images JPEG"); - if (key == QLatin1String("KEY_IMAGES_PNG") ) return tr("Images PNG"); - if (key == QLatin1String("KEY_VIDEO") ) return tr("Video (mpeg, avi...)"); + if (key == QLatin1String("KEY_ALL") ) { return tr("All Files"); } + if (key == QLatin1String("KEY_ARCHIVES") ) { return tr("Archives (zip, rar...)"); } + if (key == QLatin1String("KEY_APPLICATIONS")) { return tr("Application (exe, xpi...)"); } + if (key == QLatin1String("KEY_AUDIO") ) { return tr("Audio (mp3, wav...)"); } + if (key == QLatin1String("KEY_DOCUMENTS") ) { return tr("Documents (pdf, odf...)"); } + if (key == QLatin1String("KEY_IMAGES") ) { return tr("Images (jpg, png...)"); } + if (key == QLatin1String("KEY_IMAGES_JPEG") ) { return tr("Images JPEG"); } + if (key == QLatin1String("KEY_IMAGES_PNG") ) { return tr("Images PNG"); } + if (key == QLatin1String("KEY_VIDEO") ) { return tr("Video (mpeg, avi...)"); } } return defaultName; } diff --git a/src/core/settings.h b/src/core/settings.h index 39804cf5..d0ee463a 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -61,7 +61,7 @@ class Settings : public AbstractSettings public: explicit Settings(QObject *parent); - ~Settings() Q_DECL_OVERRIDE = default; + ~Settings() override = default; // Tab General ExistingFileOption existingFileOption() const; diff --git a/src/core/stream.cpp b/src/core/stream.cpp index 804079d9..5854ed7a 100644 --- a/src/core/stream.cpp +++ b/src/core/stream.cpp @@ -16,6 +16,7 @@ #include "stream.h" +#include #include #include @@ -37,34 +38,13 @@ #include /* std::sort */ -#if defined Q_OS_WIN -static const QString C_PROGRAM_NAME = QLatin1String("yt-dlp.exe"); -#else -static const QString C_PROGRAM_NAME = QLatin1String("yt-dlp"); -#endif - -static const QString C_WEBSITE_URL = QLatin1String("https://github.com/yt-dlp/yt-dlp"); -static const int C_EXIT_SUCCESS = 0; - -static const QString C_NONE = QLatin1String("none"); - -static const QString C_WARNING_msg_header_01 = QLatin1String("WARNING:"); -static const QString C_WARNING_msg_header_02 = QLatin1String("\\033[0;33mWARNING:\\033[0m"); -static const QString C_ERROR_msg_header_01 = QLatin1String("ERROR:"); -static const QString C_ERROR_msg_header_02 = QLatin1String("\\033[0;31mERROR:\\033[0m"); +using namespace Qt::Literals::StringLiterals; -static const QString C_WARNING_merge_output_format = QLatin1String( - "Requested formats are incompatible for merge and will be merged into mkv."); -static const QString C_DOWNLOAD_msg_header = QLatin1String("[download]"); -static const QString C_DOWNLOAD_next_section = QLatin1String("Destination:"); -static const QString C_MERGER_msg_header = QLatin1String("[Merger]"); - - -static QString s_youtubedl_version = QString(); +static QString s_youtubedl_version = {}; static int s_youtubedl_concurrent_fragments = 0; static bool s_youtubedl_last_modified_time_enabled = true; -static QString s_youtubedl_user_agent = QString(); +static QString s_youtubedl_user_agent = {}; static int s_youtubedl_socket_type = 0; static int s_youtubedl_socket_timeout = 0; @@ -89,10 +69,8 @@ Stream::Stream(QObject *parent) : QObject(parent) , m_process(new QProcess(this)) { connect(m_process, SIGNAL(started()), this, SLOT(onStarted())); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); -#endif - connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinished(int,QProcess::ExitStatus))); connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onStandardOutputReady())); connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(onStandardErrorReady())); @@ -111,8 +89,8 @@ QString Stream::version() { if (s_youtubedl_version.isEmpty()) { auto arguments = QStringList() - << QLatin1String("--no-colors") - << QLatin1String("--version"); + << "--no-colors"_L1 + << "--version"_L1; QProcess process; process.setWorkingDirectory(qApp->applicationDirPath()); process.start(C_PROGRAM_NAME, arguments); @@ -192,9 +170,9 @@ static inline bool matches(const QString &host, const QString ®exHost) auto domains = host.split('.', Qt::SkipEmptyParts); auto mandatoryDomains = regexHost.split(delimiters, Qt::SkipEmptyParts); - foreach (auto mandatory, mandatoryDomains) { + for (auto mandatory : mandatoryDomains) { bool found = false; - foreach (auto domain, domains) { + for (auto domain : domains) { if (QString::compare(domain, mandatory, Qt::CaseInsensitive) == 0) { found = true; break; @@ -209,7 +187,7 @@ static inline bool matches(const QString &host, const QString ®exHost) bool Stream::matchesHost(const QString &host, const QStringList ®exHosts) { - foreach (auto regexHost, regexHosts) { + for (auto regexHost : regexHosts) { if (matches(host, regexHost)) { return true; } @@ -223,7 +201,7 @@ void Stream::clear() { m_url.clear(); m_outputPath.clear(); - m_selectedFormatId = StreamFormatId(); + m_selectedFormatId = {}; m_bytesReceived = 0; m_bytesReceivedCurrentSection = 0; m_bytesTotal = 0; @@ -385,7 +363,7 @@ QStringList Stream::arguments() const /// \todo implement chapters writing } if (m_config.thumbnail.writeDefaultThumbnail) { - arguments << QLatin1String("--write-thumbnail"); + arguments << "--write-thumbnail"_L1; } if (m_config.comment.writeComment) { arguments << QLatin1String("--write-comments"); @@ -424,7 +402,7 @@ QStringList Stream::arguments() const break; } if (!m_referringPage.isEmpty()) { - arguments << QLatin1String("--referer") << m_referringPage; + arguments << "--referer"_L1 << m_referringPage; } if (isMergeFormat(m_fileExtension)) { arguments << QLatin1String("--merge-output-format") << m_fileExtension; @@ -440,7 +418,7 @@ QString Stream::command(int indent) const // Inline command QString cmd = C_PROGRAM_NAME + " "; - foreach (auto argument, args) { + for (auto argument : args) { auto quote = argument.contains(' ') ? QString('\"') : QString(); cmd += quote + argument + quote + " "; } @@ -449,7 +427,7 @@ QString Stream::command(int indent) const // Smartly wrapped arguments cmd += C_PROGRAM_NAME + " "; - foreach (auto argument, args) { + for (auto argument : args) { if (argument.startsWith("--")) { cmd += "\\\n" + QString().fill(' ', indent); } @@ -535,12 +513,12 @@ void Stream::onStandardErrorReady() QStringList Stream::splitMultiThreadMessages(const QString &raw) const { QStringList messages; - QRegularExpression re(R"(\[download\]|\[Merger\])", QRegularExpression::CaseInsensitiveOption); - QString raw2 = raw; - qsizetype pos = raw2.lastIndexOf(re); + static QRegularExpression re(R"(\[download\]|\[Merger\])", QRegularExpression::CaseInsensitiveOption); + auto raw2 = raw; + auto pos = raw2.lastIndexOf(re); if (0 <= pos && pos <= raw2.size()) { while (pos != -1) { - QString message = raw2.last(raw2.size() - pos); + auto message = raw2.last(raw2.size() - pos); messages.prepend(message); raw2.truncate(pos); pos = raw2.lastIndexOf(re); @@ -553,8 +531,8 @@ QStringList Stream::splitMultiThreadMessages(const QString &raw) const void Stream::parseStandardOutput(const QString &msg) { - QStringList messages = splitMultiThreadMessages(msg); - foreach (auto message, messages) { + auto messages = splitMultiThreadMessages(msg); + for (auto message : messages) { parseSingleStandardOutput(message); } } @@ -570,8 +548,8 @@ void Stream::parseSingleStandardOutput(const QString &msg) } if (areEqual(tokens.at(0), C_MERGER_msg_header)) { // During merger, the progress is arbitrarily at 99%, not 100%. - qsizetype bytesTotal = _q_bytesTotal(); - qsizetype almostFinished = static_cast(0.99 * qreal(bytesTotal)); + auto bytesTotal = _q_bytesTotal(); + auto almostFinished = static_cast(0.99 * qreal(bytesTotal)); emit downloadProgress(almostFinished, bytesTotal); return; } @@ -593,7 +571,7 @@ void Stream::parseSingleStandardOutput(const QString &msg) ? tokens.at(3) : tokens.at(4); - qreal percent = Format::parsePercentDecimal(percentToken); + auto percent = Format::parsePercentDecimal(percentToken); if (percent < 0) { qWarning("Can't parse '%s'.", percentToken.toLatin1().data()); return; @@ -604,10 +582,10 @@ void Stream::parseSingleStandardOutput(const QString &msg) qWarning("Can't parse '%s'.", sizeToken.toLatin1().data()); return; } - m_bytesReceivedCurrentSection = static_cast(qreal(percent * m_bytesTotalCurrentSection) / 100); + m_bytesReceivedCurrentSection = static_cast(percent * static_cast(m_bytesTotalCurrentSection) / 100); } - qsizetype received = m_bytesReceived + m_bytesReceivedCurrentSection; + auto received = m_bytesReceived + m_bytesReceivedCurrentSection; emit downloadProgress(received, _q_bytesTotal()); } } @@ -655,13 +633,10 @@ bool Stream::isMergeFormat(const QString &suffix) const ******************************************************************************/ StreamCleanCache::StreamCleanCache(QObject *parent) : QObject(parent) , m_process(new QProcess(this)) - , m_isCleaned(false) { connect(m_process, SIGNAL(started()), this, SLOT(onStarted())); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); -#endif - connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinished(int,QProcess::ExitStatus))); } StreamCleanCache::~StreamCleanCache() @@ -674,8 +649,8 @@ void StreamCleanCache::runAsync() { if (m_process->state() == QProcess::NotRunning) { auto arguments = QStringList() - << QLatin1String("--no-colors") - << QLatin1String("--rm-cache-dir"); + << "--no-colors"_L1 + << "--rm-cache-dir"_L1; m_process->setWorkingDirectory(qApp->applicationDirPath()); m_process->start(C_PROGRAM_NAME, arguments); debugPrintProcessCommand(m_process); @@ -686,9 +661,9 @@ QUrl StreamCleanCache::cacheDir() { // Try to get the .cache from $XDG_CACHE_HOME, if it's not set, // it has to be in ~/.cache as per XDG standard - QString dir = QString::fromUtf8(getenv("XDG_CACHE_HOME")); + auto dir = QString::fromUtf8(getenv("XDG_CACHE_HOME")); if (dir.isEmpty()) { - dir = QDir::cleanPath(QDir::homePath() + QLatin1String("/.cache")); + dir = QDir::cleanPath(QDir::homePath() + "/.cache"_L1); } return QUrl::fromLocalFile(dir); } @@ -735,12 +710,10 @@ StreamAssetDownloader::StreamAssetDownloader(QObject *parent) : QObject(parent) { connect(m_processDumpJson, SIGNAL(started()), this, SLOT(onStarted())); connect(m_processFlatList, SIGNAL(started()), this, SLOT(onStarted())); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(m_processDumpJson, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); connect(m_processFlatList, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); -#endif - connect(m_processDumpJson, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinishedDumpJson(int, QProcess::ExitStatus))); - connect(m_processFlatList, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinishedFlatList(int, QProcess::ExitStatus))); + connect(m_processDumpJson, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishedDumpJson(int,QProcess::ExitStatus))); + connect(m_processFlatList, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishedFlatList(int,QProcess::ExitStatus))); // Cache cleaner connect(m_streamCleanCache, SIGNAL(done()), this, SLOT(onCacheCleaned())); @@ -927,7 +900,7 @@ StreamAssetDownloader::StreamDumpMap StreamAssetDownloader::parseDumpMap( { StreamDumpMap map; QList stdoutLines = stdoutBytes.split(QChar('\n').toLatin1()); - foreach (auto stdoutLine, stdoutLines) { + for (auto stdoutLine : stdoutLines) { if (!stdoutLine.isEmpty()) { StreamObject streamObject = parseDumpItemStdOut(stdoutLine); map.insert(streamObject.id(), streamObject); @@ -935,7 +908,7 @@ StreamAssetDownloader::StreamDumpMap StreamAssetDownloader::parseDumpMap( } } QList stderrLines = stderrBytes.split(QChar('\n').toLatin1()); - foreach (auto stderrLine, stderrLines) { + for (auto stderrLine : stderrLines) { if (!stderrLine.isEmpty()) { StreamObject streamObject = parseDumpItemStdErr(stderrLine); map.insert(streamObject.id(), streamObject); @@ -950,10 +923,10 @@ static void parseSubtitles( StreamObject::Data *data = nullptr) { Q_ASSERT(data); - foreach (const QString &languageCode, jsonSubtitles.keys()) { + for (const auto &languageCode : jsonSubtitles.keys()) { QJsonValue jsonLanguage = jsonSubtitles.value(languageCode); QJsonArray jsonExtensions = jsonLanguage.toArray(); - foreach (auto jsonExtension, jsonExtensions) { + for (auto jsonExtension : jsonExtensions) { QJsonObject jsonSub = jsonExtension.toObject(); StreamSubtitle subtitle; subtitle.languageCode = languageCode; @@ -1005,7 +978,7 @@ StreamObject StreamAssetDownloader::parseDumpItemStdOut(const QByteArray &bytes) data.title = title; QJsonArray jsonFormats = json[QLatin1String("formats")].toArray(); - foreach (auto jsonFormat, jsonFormats) { + for (auto jsonFormat : jsonFormats) { QJsonObject jsonFmt = jsonFormat.toObject(); StreamFormat format; @@ -1124,7 +1097,7 @@ StreamAssetDownloader::StreamFlatList StreamAssetDownloader::parseFlatList( { QList list; QList stdoutLines = stdoutBytes.split(QChar('\n').toLatin1()); - foreach (auto stdoutLine, stdoutLines) { + for (auto stdoutLine : stdoutLines) { if (!stdoutLine.isEmpty()) { StreamFlatListItem item = parseFlatItem(stdoutLine); if (!item.id.isEmpty()) { @@ -1133,7 +1106,7 @@ StreamAssetDownloader::StreamFlatList StreamAssetDownloader::parseFlatList( } } QList stderrLines = stderrBytes.split(QChar('\n').toLatin1()); - foreach (auto stderrLine, stderrLines) { + for (auto stderrLine : stderrLines) { if (!stderrLine.isEmpty()) { qWarning("Stream error: '%s'.", stderrLine.data()); } @@ -1167,7 +1140,7 @@ void StreamAssetDownloader::onFinished() if (!m_dumpMap.isEmpty() && !m_flatList.isEmpty()) { QList streamObjects; int playlist_index = 0; - foreach (auto flatItem, m_flatList) { + for (auto flatItem : m_flatList) { playlist_index++; StreamObject si = createStreamObject(flatItem); si.data().playlist_index = QString::number(playlist_index); @@ -1207,10 +1180,8 @@ StreamUpgrader::StreamUpgrader(QObject *parent) : QObject(parent) , m_process(new QProcess(this)) { connect(m_process, SIGNAL(started()), this, SLOT(onStarted())); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); -#endif - connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); + connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinished(int,QProcess::ExitStatus))); connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(onStandardOutputReady())); connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(onStandardErrorReady())); } @@ -1274,12 +1245,10 @@ StreamExtractorListCollector::StreamExtractorListCollector(QObject *parent) : QO { connect(m_processExtractors, SIGNAL(started()), this, SLOT(onStarted())); connect(m_processDescriptions, SIGNAL(started()), this, SLOT(onStarted())); -#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(m_processExtractors, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); connect(m_processDescriptions, SIGNAL(errorOccurred(QProcess::ProcessError)), this, SLOT(onError(QProcess::ProcessError))); -#endif - connect(m_processExtractors, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinishedExtractors(int, QProcess::ExitStatus))); - connect(m_processDescriptions, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinishedDescriptions(int, QProcess::ExitStatus))); + connect(m_processExtractors, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishedExtractors(int,QProcess::ExitStatus))); + connect(m_processDescriptions, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishedDescriptions(int,QProcess::ExitStatus))); } StreamExtractorListCollector::~StreamExtractorListCollector() @@ -1390,7 +1359,7 @@ void StreamFormatId::fromString(const QString &format_id) QList StreamFormatId::compoundIds() const { QList ret; - foreach (auto identifier, m_identifiers) { + for (auto identifier : m_identifiers) { ret << StreamFormatId(identifier); } return ret; @@ -1488,7 +1457,7 @@ QString StreamObject::Data::Format::toString() const .arg(abr) .arg(acodec); } - return QString(); + return {}; } QString StreamObject::Data::Format::debug_description() const @@ -1664,8 +1633,8 @@ QString StreamObject::suffix(const StreamFormatId &formatId) const return m_data.defaultSuffix; } auto suffix = m_data.defaultSuffix; - foreach (auto id, formatId.compoundIds()) { - foreach (auto format, m_data.formats) { + for (auto id : formatId.compoundIds()) { + for (auto format : m_data.formats) { if (id == format.formatId) { if (format.hasVideo()) { return format.ext; @@ -1689,14 +1658,14 @@ StreamFormatId StreamObject::formatId() const void StreamObject::setFormatId(const StreamFormatId &formatId) { - m_userSuffix = QString(); + m_userSuffix = {}; m_userFormatId = (formatId == m_data.defaultFormatId) ? StreamFormatId() : formatId; } QString StreamObject::formatToString() const { QString ret; - foreach (auto id, formatId().compoundIds()) { + for (auto id : formatId().compoundIds()) { for (auto format : m_data.formats) { if (id == format.formatId) { if (!ret.isEmpty()) { @@ -1713,7 +1682,7 @@ QList StreamObject::Data::defaultFormats() const { // Map avoids duplicate entries QMap map; - foreach (auto format, formats) { + for (auto format : formats) { if (format.hasVideo() && format.hasMusic()) { // The output list should be sorted in ascending order of @@ -1732,7 +1701,7 @@ QList StreamObject::Data::defaultFormats() const QList StreamObject::Data::audioFormats() const { QList list; - foreach (auto format, formats) { + for (auto format : formats) { if (!format.hasVideo() && format.hasMusic()) { list.append(format); } @@ -1743,7 +1712,7 @@ QList StreamObject::Data::audioFormats() const QList StreamObject::Data::videoFormats() const { QList list; - foreach (auto format, formats) { + for (auto format : formats) { if (format.hasVideo() && !format.hasMusic()) { list.append(format); } @@ -1759,7 +1728,7 @@ QList StreamObject::Data::videoFormats() const QList StreamObject::Data::subtitleLanguages() const { QMap map; - foreach (auto subtitle, subtitles) { + for (auto subtitle : subtitles) { QString key = subtitle.languageCode + " " + subtitle.languageName + " " + @@ -1774,7 +1743,7 @@ QList StreamObject::Data::subtitleExtensions() const { // QSet avoids duplicate entries QSet set; - foreach (auto subtitle, subtitles) { + for (auto subtitle : subtitles) { set.insert(subtitle.ext); } return set.values(); // unsorted @@ -1806,7 +1775,7 @@ QString StreamObject::Data::debug_description() const defaultFormatId.toString(), playlist, playlist_index))); - foreach (auto format, formats) { + for (auto format : formats) { descr.append("\n"); descr.append(format.debug_description()); } @@ -1848,7 +1817,7 @@ static QString generateErrorMessage(QProcess::ProcessError error) default: Q_UNREACHABLE(); } - return QString(); + return {}; } static QString toString(QProcess *process) @@ -1927,7 +1896,7 @@ void debugPrintProcessCommand(QProcess *process) QString text = ""; text += process->program(); text += " "; - foreach (auto arg, process->arguments()) { + for (auto arg : process->arguments()) { text += arg; text += " "; } diff --git a/src/core/stream.h b/src/core/stream.h index 668b34b4..1cc23c54 100644 --- a/src/core/stream.h +++ b/src/core/stream.h @@ -77,7 +77,7 @@ class StreamFormatId }; /* Enable the type to be used with QVariant. */ -Q_DECLARE_METATYPE(StreamFormatId); +Q_DECLARE_METATYPE(StreamFormatId) inline size_t qHash(const StreamFormatId &key, size_t seed) { @@ -450,7 +450,7 @@ class Stream : public QObject public: explicit Stream(QObject *parent); - ~Stream() Q_DECL_OVERRIDE; + ~Stream() override; static QString version(); static QString website(); @@ -546,7 +546,7 @@ class StreamCleanCache : public QObject Q_OBJECT public: explicit StreamCleanCache(QObject *parent); - ~StreamCleanCache() Q_DECL_OVERRIDE; + ~StreamCleanCache() override; static QUrl cacheDir(); @@ -562,8 +562,8 @@ private slots: void onFinished(int exitCode, QProcess::ExitStatus exitStatus); private: - QProcess *m_process; - bool m_isCleaned; + QProcess *m_process = nullptr; + bool m_isCleaned = false; }; class StreamAssetDownloader : public QObject @@ -572,17 +572,18 @@ class StreamAssetDownloader : public QObject public: struct StreamFlatListItem { - QString _type; + QString _type = {}; StreamObjectId id; QString ie_key; QString title; QString url; }; + using StreamFlatList = QList; using StreamDumpMap = QMap; explicit StreamAssetDownloader(QObject *parent); - ~StreamAssetDownloader() Q_DECL_OVERRIDE; + ~StreamAssetDownloader() override; void runAsync(const QString &url); void stop(); @@ -631,7 +632,7 @@ class StreamVersion : public QThread public: StreamVersion(QObject *parent = nullptr): QThread(parent) {} - void run() Q_DECL_OVERRIDE; + void run() override; void stop(); signals: @@ -646,7 +647,7 @@ class StreamUpgrader : public QObject Q_OBJECT public: explicit StreamUpgrader(QObject *parent); - ~StreamUpgrader() Q_DECL_OVERRIDE; + ~StreamUpgrader() override; void runAsync(); @@ -669,7 +670,7 @@ class StreamExtractorListCollector : public QObject Q_OBJECT public: explicit StreamExtractorListCollector(QObject *parent); - ~StreamExtractorListCollector() Q_DECL_OVERRIDE; + ~StreamExtractorListCollector() override; void runAsync(); @@ -704,8 +705,10 @@ char *toString(const StreamObject &streamObject); #endif /* Enable the type to be used with QVariant. */ -Q_DECLARE_METATYPE(StreamFormat); -Q_DECLARE_METATYPE(StreamObject); +Q_DECLARE_METATYPE(StreamFormat) + +Q_DECLARE_METATYPE(StreamObject) + #ifdef QT_DEBUG QT_BEGIN_NAMESPACE diff --git a/src/core/streammanager.h b/src/core/streammanager.h index f3f3d4dd..46e4e1a2 100644 --- a/src/core/streammanager.h +++ b/src/core/streammanager.h @@ -30,7 +30,7 @@ class StreamManager : public QObject public: explicit StreamManager(QObject *parent = nullptr); - ~StreamManager() Q_DECL_OVERRIDE = default; + ~StreamManager() override = default; Settings* settings() const; void setSettings(Settings *settings); @@ -45,7 +45,7 @@ private slots: void onSettingsChanged(); private: - Settings *m_settings{Q_NULLPTR}; + Settings *m_settings{nullptr}; void setProxySettings(Settings *settings); }; diff --git a/src/core/theme.cpp b/src/core/theme.cpp index 1db88842..e53f4ad6 100644 --- a/src/core/theme.cpp +++ b/src/core/theme.cpp @@ -16,6 +16,7 @@ #include "theme.h" +#include #include #include @@ -32,26 +33,19 @@ /* Public static constants */ -const QLatin1String Theme::PlatformStyle("platformStyle"); -const QLatin1String Theme::IconTheme("iconTheme"); -const QLatin1String Theme::ColorScheme("colorScheme"); +const QLatin1StringView Theme::PlatformStyle("platformStyle"); +const QLatin1StringView Theme::IconTheme("iconTheme"); +const QLatin1StringView Theme::ColorScheme("colorScheme"); /* Private static constants */ static QString s_themeSearchPath = QString::fromUtf8(":/resources/icons/"); -/* Settings flags */ -static QLatin1String s_themeDefault("default"); -static QLatin1String s_themeFlat("flat"); -static QLatin1String s_schemeLight("light"); -static QLatin1String s_schemeDark("dark"); - - /* Runtime Debug Purpose */ static void _assertNoMissingIconTheme(const QWidget *widget) { auto widgetName = widget->windowTitle().toLatin1().data(); QList buttons = widget->findChildren(); - foreach (QAbstractButton* button, buttons) { + for (auto *button : buttons) { if ( button->objectName() == QLatin1String("qt_menubar_ext_button") || button->objectName() == QLatin1String("qt_toolbar_ext_button")) { continue; @@ -64,7 +58,7 @@ static void _assertNoMissingIconTheme(const QWidget *widget) } } QList actions = widget->findChildren(); - foreach (QAction* action, actions) { + for (auto *action : actions) { if (!action->icon().isNull() && action->icon().name().isEmpty()) { qWarning("Missing icon theme name for QAction '%s' ('%s') in QWidget '%s'.", action->objectName().toLatin1().data(), @@ -85,7 +79,7 @@ QStringList Theme::availablePlatformStyles() return QStyleFactory::keys(); } -QString Theme::toPlatformStyle(int index) +QString Theme::toPlatformStyle(qsizetype index) { auto keys = QStyleFactory::keys(); if (index >= 0 && index < keys.count()) { @@ -94,7 +88,7 @@ QString Theme::toPlatformStyle(int index) return QLatin1String(""); // Must be an empty string, not a null QString } -int Theme::fromPlatformStyle(const QString &platformStyle) +qsizetype Theme::fromPlatformStyle(const QString &platformStyle) { auto index = QStyleFactory::keys().indexOf(platformStyle); return index == -1 ? 0 : index; @@ -110,8 +104,8 @@ QStringList Theme::availableIconThemes() QString Theme::toIconTheme(int index) { switch (index) { - case 0: return s_themeDefault; - case 1: return s_themeFlat; + case 0: return THEME_DEFAULT; + case 1: return THEME_FLAT; default: break; } return QLatin1String(""); // Must be an empty string, not a null QString @@ -119,9 +113,9 @@ QString Theme::toIconTheme(int index) int Theme::fromIconTheme(const QString &iconTheme) { - if (iconTheme.compare(s_themeDefault, Qt::CaseInsensitive) == 0) { + if (iconTheme.compare(THEME_DEFAULT, Qt::CaseInsensitive) == 0) { return 0; - } else if (iconTheme.compare(s_themeFlat, Qt::CaseInsensitive) == 0) { + } else if (iconTheme.compare(THEME_FLAT, Qt::CaseInsensitive) == 0) { return 1; } return 0; @@ -137,8 +131,8 @@ QStringList Theme::availableColorSchemes() QString Theme::toColorScheme(int index) { switch (index) { - case 0: return s_schemeLight; - case 1: return s_schemeDark; + case 0: return SCHEME_LIGHT; + case 1: return SCHEME_DARK; default: break; } return QLatin1String(""); // Must be an empty string, not a null QString @@ -146,9 +140,9 @@ QString Theme::toColorScheme(int index) int Theme::fromColorScheme(const QString &colorScheme) { - if (colorScheme.compare(s_schemeLight, Qt::CaseInsensitive) == 0) { + if (colorScheme.compare(SCHEME_LIGHT, Qt::CaseInsensitive) == 0) { return 0; - } else if (colorScheme.compare(s_schemeDark, Qt::CaseInsensitive) == 0) { + } else if (colorScheme.compare(SCHEME_DARK, Qt::CaseInsensitive) == 0) { return 1; } return 0; @@ -195,9 +189,7 @@ static void polishDark(QPalette &palette) palette.setColor(QPalette::ToolTipBase, Qt::white); palette.setColor(QPalette::ToolTipText, QColor(53, 53, 53)); // -- -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) palette.setColor(QPalette::PlaceholderText, QColor(127, 127, 127)); // custom -#endif // -- } @@ -208,11 +200,9 @@ void Theme::applyTheme(const QMap &map) if (!QIcon::themeSearchPaths().contains(s_themeSearchPath)) { QIcon::setThemeSearchPaths(QIcon::themeSearchPaths() << s_themeSearchPath); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 0) if (QIcon::fallbackThemeName().isEmpty()) { QIcon::setFallbackThemeName(QLatin1String("default")); } -#endif const QString platformStyle = map.value(Theme::PlatformStyle, QString()).toString(); const QString iconTheme = map.value(Theme::IconTheme, QString()).toString(); @@ -241,38 +231,38 @@ void Theme::applyTheme(const QMap &map) /*! * QtDesigner doesn't icon themes correctly, this is a workaround */ -void Theme::setIcons(const QWidget *widget, const QMap &map) +void Theme::setIcons(const QWidget *widget, const QHash &hash) { - QMapIterator it(map); + QHashIterator it(hash); while (it.hasNext()) { it.next(); - auto button = it.key(); + auto qbutton = it.key(); auto name = it.value(); - button->setIcon(QIcon::fromTheme(name)); + qbutton->setIcon(QIcon::fromTheme(name)); } _assertNoMissingIconTheme(widget); } -void Theme::setIcons(const QWidget *widget, const QMap &map) +void Theme::setIcons(const QWidget *widget, const QHash &hash) { - QMapIterator it(map); + QHashIterator it(hash); while (it.hasNext()) { it.next(); - auto action = it.key(); + auto qaction = it.key(); auto name = it.value(); - action->setIcon(QIcon::fromTheme(name)); + qaction->setIcon(QIcon::fromTheme(name)); } _assertNoMissingIconTheme(widget); } -void Theme::setIcons(const QWidget *widget, const QMap &map, int extent) +void Theme::setIcons(const QWidget *widget, const QHash &hash, int extent) { - QMapIterator it(map); + QHashIterator it(hash); while (it.hasNext()) { it.next(); - auto label = it.key(); + auto qlabel = it.key(); auto name = it.value(); - label->setPixmap(QIcon::fromTheme(name).pixmap(extent)); + qlabel->setPixmap(QIcon::fromTheme(name).pixmap(extent)); } _assertNoMissingIconTheme(widget); } diff --git a/src/core/theme.h b/src/core/theme.h index 5342aeef..facd8748 100644 --- a/src/core/theme.h +++ b/src/core/theme.h @@ -29,15 +29,15 @@ class QWidget; class Theme { public: - static const QLatin1String PlatformStyle; - static const QLatin1String IconTheme; - static const QLatin1String ColorScheme; + static const QLatin1StringView PlatformStyle; + static const QLatin1StringView IconTheme; + static const QLatin1StringView ColorScheme; Theme(); static QStringList availablePlatformStyles(); - static QString toPlatformStyle(int index); - static int fromPlatformStyle(const QString &platformStyle); + static QString toPlatformStyle(qsizetype index); + static qsizetype fromPlatformStyle(const QString &platformStyle); static QStringList availableIconThemes(); static QString toIconTheme(int index); @@ -50,9 +50,9 @@ class Theme static void applyTheme(const QMap &map); /* Utils */ - static void setIcons(const QWidget *widget, const QMap &map); - static void setIcons(const QWidget *widget, const QMap &map); - static void setIcons(const QWidget *widget, const QMap &map, int extent = 48); + static void setIcons(const QWidget *widget, const QHash &hash); + static void setIcons(const QWidget *widget, const QHash &hash); + static void setIcons(const QWidget *widget, const QHash &hash, int extent = 48); }; #endif // WIDGETS_THEME_H diff --git a/src/core/torrent.cpp b/src/core/torrent.cpp index 20b1fb70..0317f4af 100644 --- a/src/core/torrent.cpp +++ b/src/core/torrent.cpp @@ -16,6 +16,7 @@ #include "torrent.h" +#include #include #include @@ -26,15 +27,12 @@ # include #endif -constexpr int max_peer_list_count = 1024; - -Torrent::Torrent(QObject *parent) : QObject(parent) +Torrent::Torrent(QObject *parent) : QObject(parent), + m_fileModel(new TorrentFileTableModel(this)), + m_peerModel(new TorrentPeerTableModel(this)), + m_trackerModel(new TorrentTrackerTableModel(this)) { - m_fileModel = new TorrentFileTableModel(this); - m_peerModel = new TorrentPeerTableModel(this); - m_trackerModel = new TorrentTrackerTableModel(this); - clear(); } @@ -160,7 +158,7 @@ void Torrent::setError(TorrentError::Type errorType, const QString &message) /****************************************************************************** ******************************************************************************/ -int Torrent::fileCount() const +qsizetype Torrent::fileCount() const { return m_detail.files.count(); } @@ -188,7 +186,7 @@ void Torrent::setFilePriority(int index, TorrentFileInfo::Priority priority) QString Torrent::preferredFilePriorities() const { QString code; - for (int fi = 0; fi < fileCount(); ++fi) { + for (auto fi = 0; fi < fileCount(); ++fi) { auto priority = filePriority(fi); switch (priority) { case TorrentFileInfo::Ignore: code.append("-"); break; @@ -203,7 +201,7 @@ QString Torrent::preferredFilePriorities() const void Torrent::setPreferredFilePriorities(const QString &priorities) { bool hasChanged = false; - for (int fi = 0; fi < fileCount(); ++fi) { + for (auto fi = 0; fi < fileCount(); ++fi) { if (fi < priorities.length()) { auto priority = TorrentFileInfo::Normal; switch (priorities.at(fi).toLatin1()) { @@ -240,7 +238,7 @@ void Torrent::removeUnconnectedPeers() /****************************************************************************** ******************************************************************************/ -int Torrent::trackerCount() const +qsizetype Torrent::trackerCount() const { return m_detail.trackers.size(); } @@ -303,7 +301,7 @@ int Torrent::progress() const break; } if (bytesTotal > 0) { - return qMin(qFloor(qreal(100 * bytesReceived) / bytesTotal), 100); + return qMin(qFloor(100 * static_cast(bytesReceived) / static_cast(bytesTotal)), 100); } return -1; // Undefined } @@ -343,7 +341,7 @@ QVariant AbstractTorrentTableModel::headerData(int section, Qt::Orientation orie if (section >= 0 && section < m_headers.count()) { return m_headers.at(section); } - return QString(); + return {}; } return QAbstractItemModel::headerData(section, orientation, role); } @@ -376,24 +374,22 @@ void TorrentFileTableModel::retranslateUi() int TorrentFileTableModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_filesMeta.count(); + return parent.isValid() ? 0 : static_cast(m_filesMeta.count()); } /// \todo move to torrentmessage? -int TorrentFileTableModel::percent(const TorrentFileMetaInfo &mi, - const TorrentFileInfo &ti) const +int TorrentFileTableModel::percent(const TorrentFileMetaInfo &mi, const TorrentFileInfo &ti) const { if (mi.bytesTotal != 0) { - return static_cast(qreal(100 * ti.bytesReceived) / mi.bytesTotal); - } else { - return 0; + return qFloor(100 * static_cast(ti.bytesReceived) / static_cast(mi.bytesTotal)); } + return 0; } qint64 TorrentFileTableModel::firstPieceIndex(const TorrentFileMetaInfo &mi) const { if (m_pieceByteSize != 0) { - return static_cast(qreal(mi.bytesOffset) / m_pieceByteSize); + return static_cast(static_cast(mi.bytesOffset) / static_cast(m_pieceByteSize)); } return 0; } @@ -401,7 +397,7 @@ qint64 TorrentFileTableModel::firstPieceIndex(const TorrentFileMetaInfo &mi) con qint64 TorrentFileTableModel::lastPieceIndex(const TorrentFileMetaInfo &mi) const { if (m_pieceByteSize != 0) { - return static_cast(qreal(mi.bytesOffset + mi.bytesTotal) / m_pieceByteSize); + return static_cast(static_cast(mi.bytesOffset + mi.bytesTotal) / static_cast(m_pieceByteSize)); } return 0; } @@ -419,15 +415,15 @@ qint64 TorrentFileTableModel::pieceCount(const TorrentFileMetaInfo &mi) const QBitArray TorrentFileTableModel::pieceSegments(const TorrentFileMetaInfo &mi) const { if (m_downloadedPieces.isEmpty()) { - return QBitArray(); + return {}; } auto offset = firstPieceIndex(mi); auto size = pieceCount(mi); if (offset < 0 || size < 0 || m_downloadedPieces.size() < offset + size) { - return QBitArray(); + return {}; } QBitArray ba(size, false); - for (int i = 0; i < size; ++i) { + for (auto i = 0; i < size; ++i) { if (m_downloadedPieces.testBit(offset + i)) { ba.setBit(i); } @@ -438,13 +434,13 @@ QBitArray TorrentFileTableModel::pieceSegments(const TorrentFileMetaInfo &mi) co QVariant TorrentFileTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (index.row() >= rowCount() || index.row() < 0) { - return QVariant(); + return {}; } - const int fileIndex = index.row(); - const TorrentFileMetaInfo mi = m_filesMeta.at(fileIndex); + auto fileIndex = index.row(); + auto mi = m_filesMeta.at(fileIndex); TorrentFileInfo ti; if (fileIndex < m_files.count()) { ti = m_files.at(fileIndex); @@ -507,7 +503,7 @@ QVariant TorrentFileTableModel::data(const QModelIndex &index, int role) const case 5: return QString("%0%").arg(QString::number(percent(mi, ti))); case 6: return firstPieceIndex(mi); case 7: return pieceCount(mi); - case 8: return QVariant(); // Progress bar + case 8: return {}; // Progress bar case 9: return ti.priorityString(); case 10: return mi.modifiedTime; case 11: return mi.hash; @@ -524,7 +520,7 @@ QVariant TorrentFileTableModel::data(const QModelIndex &index, int role) const case 3: case 4: case 5: - case 6:return QVariant(); + case 6:return {}; case 7: case 8: { auto done = QString::number(percent(mi, ti)); @@ -534,12 +530,12 @@ QVariant TorrentFileTableModel::data(const QModelIndex &index, int role) const case 9: case 10: case 11: - case 12: return QVariant(); + case 12: return {}; default: break; } } - return QVariant(); + return {}; } void TorrentFileTableModel::refreshMetaData(const QList &files) @@ -548,7 +544,7 @@ void TorrentFileTableModel::refreshMetaData(const QList &fi m_filesMeta = files; m_files.clear(); - auto torrent = static_cast(parent()); + auto torrent = dynamic_cast(parent()); if (torrent) { m_pieceByteSize = torrent->metaInfo().initialMetaInfo.pieceByteSize; } @@ -559,7 +555,7 @@ void TorrentFileTableModel::refreshMetaData(const QList &fi void TorrentFileTableModel::refreshData(const QList &files) { m_files = files; - auto torrent = static_cast(parent()); + auto torrent = dynamic_cast(parent()); if (torrent) { m_downloadedPieces = torrent->info().downloadedPieces; } @@ -571,7 +567,7 @@ void TorrentFileTableModel::refreshData(const QList &files) TorrentPeerTableModel::TorrentPeerTableModel(Torrent *parent) : AbstractTorrentTableModel(parent) { - m_peers.reserve(max_peer_list_count); + m_peers.reserve(MAX_PEER_LIST_COUNT); retranslateUi(); } @@ -593,18 +589,18 @@ void TorrentPeerTableModel::retranslateUi() int TorrentPeerTableModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_peers.count(); + return parent.isValid() ? 0 : static_cast(m_peers.count()); } QVariant TorrentPeerTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (index.row() >= rowCount() || index.row() < 0) { - return QVariant(); + return {}; } - const TorrentPeerInfo peer = m_peers.at(index.row()); + auto peer = m_peers.at(index.row()); if (role == Qt::TextAlignmentRole) { switch (index.column()) { case 0: @@ -626,9 +622,9 @@ QVariant TorrentPeerTableModel::data(const QModelIndex &index, int role) const } } else if (role == ProgressRole) { - auto done = peer.availablePieces.count(true); - auto total = peer.availablePieces.count(); - return total > 0 ? qMin(qCeil(qreal(100 * done) / total), 100) : 0; + auto done = static_cast(peer.availablePieces.count(true)); + auto total = static_cast(peer.availablePieces.count()); + return total > 0 ? qMin(qCeil(100 * done / total), 100) : 0; } else if (role == SegmentRole) { return peer.availablePieces; @@ -660,7 +656,7 @@ QVariant TorrentPeerTableModel::data(const QModelIndex &index, int role) const case 2: return peer.userAgent; case 3: return Format::fileSizeToString(peer.bytesDownloaded); case 4: return Format::fileSizeToString(peer.bytesUploaded); - case 5: return QVariant(); // Progress bar + case 5: return {}; // Progress bar case 6: return Format::timeToString(peer.lastTimeRequested); case 7: return Format::timeToString(peer.lastTimeActive); case 8: return Format::timeToString(peer.timeDownloadQueue); @@ -676,7 +672,7 @@ QVariant TorrentPeerTableModel::data(const QModelIndex &index, int role) const case 1: case 2: case 3: - case 4: return QVariant(); + case 4: return {}; case 5: { auto done = QString::number(peer.availablePieces.count(true)); auto total = QString::number(peer.availablePieces.count()); @@ -684,21 +680,21 @@ QVariant TorrentPeerTableModel::data(const QModelIndex &index, int role) const } case 6: case 7: - case 8: return QVariant(); + case 8: return {}; case 9: return TorrentPeerInfo::flagTooltip(); case 10: return TorrentPeerInfo::sourceFlagTooltip(); default: break; } } - return QVariant(); + return {}; } void TorrentPeerTableModel::removeUnconnectedPeers() { beginResetModel(); QList peers; - foreach (auto peer, m_peers) { + for (auto peer : m_peers) { if (m_connectedPeers.contains(peer.endpoint)) { peers.append(peer); } @@ -715,16 +711,17 @@ void TorrentPeerTableModel::refreshData(const QList &peers) m_connectedPeers.clear(); QList newItems; - foreach (auto newItem, peers) { + for (auto newItem : peers) { m_connectedPeers.insert(newItem.endpoint); bool replaced = false; - for (int i = 0, count = m_peers.count(); i < count; ++i) { + for (auto i = 0; i < m_peers.count(); ++i) { auto item = m_peers.at(i); // Try update if (item.endpoint == newItem.endpoint) { m_peers.replace(i, newItem); - emit dataChanged(index(i, 0), index(i, columnCount()), {Qt::DisplayRole}); + auto row = static_cast(i); + emit dataChanged(index(row, 0), index(row, columnCount()), {Qt::DisplayRole}); replaced = true; break; } @@ -743,23 +740,24 @@ void TorrentPeerTableModel::appendRemainingSafely(const QList & return; } int ptr = 0; - if (m_peers.count() < max_peer_list_count) { - ptr = qMin(newItems.count(), max_peer_list_count - m_peers.count()); + if (m_peers.count() < MAX_PEER_LIST_COUNT) { + ptr = qMin(newItems.count(), MAX_PEER_LIST_COUNT - m_peers.count()); - const int first = m_peers.count(); - const int last = qMin(first + ptr - 1, max_peer_list_count - 1); + auto first = m_peers.count(); + auto last = qMin(first + ptr - 1, MAX_PEER_LIST_COUNT - 1); beginInsertRows(QModelIndex(), first, last); m_peers.append(newItems.mid(0, ptr)); endInsertRows(); } if (ptr < newItems.count()) { - for (int i = m_peers.count() - 1; i >= 0; --i) { + for (auto i = m_peers.count() - 1; i >= 0; --i) { auto peer = m_peers.at(i); if (m_connectedPeers.contains(peer.endpoint)) { continue; } m_peers.replace(i, newItems.at(ptr)); - emit dataChanged(index(i, 0), index(i, columnCount()), {Qt::DisplayRole}); + auto row = static_cast(i); + emit dataChanged(index(row, 0), index(row, columnCount()), {Qt::DisplayRole}); ptr++; if (ptr >=newItems.count() ) { break; @@ -790,16 +788,16 @@ void TorrentTrackerTableModel::retranslateUi() int TorrentTrackerTableModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_trackers.count(); + return parent.isValid() ? 0 : static_cast(m_trackers.count()); } QVariant TorrentTrackerTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (index.row() >= rowCount() || index.row() < 0) { - return QVariant(); + return {}; } if (role == Qt::TextAlignmentRole) { switch (index.column()) { @@ -831,7 +829,7 @@ QVariant TorrentTrackerTableModel::data(const QModelIndex &index, int role) cons break; } } - return QVariant(); + return {}; } void TorrentTrackerTableModel::refreshData(const QList &trackers) @@ -840,21 +838,22 @@ void TorrentTrackerTableModel::refreshData(const QList &trac return; } - QModelIndex parent = QModelIndex(); // empty is always root + QModelIndex parent = {}; // empty is always root QList newItems; - for (int i = 0, count = trackers.count(); i < count; ++i) { + for (auto i = 0; i < trackers.count(); ++i) { auto newItem = trackers.at(i); bool replaced = false; - for (int j = 0, count2 = m_trackers.count(); j < count2; ++j) { + for (auto j = 0; j < m_trackers.count(); ++j) { auto item = m_trackers.at(j); // Try update if (item.url == newItem.url) { m_trackers.removeAt(j); m_trackers.insert(j, newItem); - emit dataChanged(index(j, 0), index(j, columnCount()), {Qt::DisplayRole}); + auto row = static_cast(j); + emit dataChanged(index(row, 0), index(row, columnCount()), {Qt::DisplayRole}); replaced = true; break; } @@ -865,8 +864,8 @@ void TorrentTrackerTableModel::refreshData(const QList &trac } // Otherwise append if (!newItems.isEmpty()) { - const int first = m_trackers.count(); - const int last = first + newItems.count() - 1; + auto first = static_cast(m_trackers.count()); + auto last = first + static_cast(newItems.count()) - 1; beginInsertRows(parent, first, last); m_trackers.append(newItems); endInsertRows(); diff --git a/src/core/torrent.h b/src/core/torrent.h index 5a20ca64..dbf85a62 100644 --- a/src/core/torrent.h +++ b/src/core/torrent.h @@ -33,8 +33,8 @@ class Torrent : public QObject Q_OBJECT public: - explicit Torrent(QObject *parent = Q_NULLPTR); - ~Torrent() Q_DECL_OVERRIDE = default; + explicit Torrent(QObject *parent = nullptr); + ~Torrent() override = default; void clear(); bool isEmpty(); @@ -64,7 +64,7 @@ class Torrent : public QObject void setError(TorrentError::Type errorType, const QString &message); - int fileCount() const; + qsizetype fileCount() const; TorrentFileInfo::Priority filePriority(int index) const; void setFilePriority(int index, TorrentFileInfo::Priority priority); @@ -75,7 +75,7 @@ class Torrent : public QObject void addPeer(const QString &input); void removeUnconnectedPeers(); - int trackerCount() const; + qsizetype trackerCount() const; void addTracker(const QString &url); void removeTrackerAt(int index); @@ -91,17 +91,17 @@ class Torrent : public QObject void changed(); private: - QString m_url; - QString m_localTorrentFileName; - QString m_outputPath; + QString m_url = {}; + QString m_localTorrentFileName = {}; + QString m_outputPath = {}; - TorrentMetaInfo m_metaInfo; - TorrentInfo m_info; - TorrentHandleInfo m_detail; + TorrentMetaInfo m_metaInfo = {}; + TorrentInfo m_info = {}; + TorrentHandleInfo m_detail = {}; - TorrentFileTableModel* m_fileModel; - TorrentPeerTableModel* m_peerModel; - TorrentTrackerTableModel* m_trackerModel; + TorrentFileTableModel* m_fileModel = nullptr; + TorrentPeerTableModel* m_peerModel = nullptr; + TorrentTrackerTableModel* m_trackerModel = nullptr; }; /****************************************************************************** @@ -110,7 +110,7 @@ class SortFilterProxyModel: public QSortFilterProxyModel { Q_OBJECT public: - explicit SortFilterProxyModel(QObject *parent = Q_NULLPTR); + explicit SortFilterProxyModel(QObject *parent = nullptr); }; /****************************************************************************** @@ -126,15 +126,14 @@ class AbstractTorrentTableModel: public QAbstractTableModel SortRole }; - explicit AbstractTorrentTableModel(Torrent *parent = Q_NULLPTR); + explicit AbstractTorrentTableModel(Torrent *parent = nullptr); - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; protected: - QStringList m_headers; + QStringList m_headers = {}; }; /****************************************************************************** @@ -143,10 +142,10 @@ class TorrentFileTableModel: public AbstractTorrentTableModel { Q_OBJECT public: - explicit TorrentFileTableModel(Torrent *parent = Q_NULLPTR); + explicit TorrentFileTableModel(Torrent *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void refreshMetaData(const QList &files); void refreshData(const QList &files); @@ -157,7 +156,8 @@ class TorrentFileTableModel: public AbstractTorrentTableModel QList m_files; qsizetype m_pieceByteSize = 0; - QBitArray m_downloadedPieces; + QBitArray m_downloadedPieces = {}; + int percent(const TorrentFileMetaInfo &mi, const TorrentFileInfo &ti) const; qint64 firstPieceIndex(const TorrentFileMetaInfo &mi) const; qint64 lastPieceIndex(const TorrentFileMetaInfo &mi) const; @@ -176,10 +176,10 @@ class TorrentPeerTableModel: public AbstractTorrentTableModel { Q_OBJECT public: - explicit TorrentPeerTableModel(Torrent *parent = Q_NULLPTR); + explicit TorrentPeerTableModel(Torrent *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void refreshData(const QList &peers); void retranslateUi(); @@ -199,10 +199,10 @@ class TorrentTrackerTableModel: public AbstractTorrentTableModel { Q_OBJECT public: - explicit TorrentTrackerTableModel(Torrent *parent = Q_NULLPTR); + explicit TorrentTrackerTableModel(Torrent *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; void refreshData(const QList &trackers); void retranslateUi(); diff --git a/src/core/torrentbasecontext.cpp b/src/core/torrentbasecontext.cpp index 33c43c49..a13d1090 100644 --- a/src/core/torrentbasecontext.cpp +++ b/src/core/torrentbasecontext.cpp @@ -18,6 +18,8 @@ #include +const double ONE_THIRD = 0.3334; +const double TWO_THIRDS = 0.6667; void TorrentBaseContext::setPriority(Torrent *torrent, int fileIndex, TorrentFileInfo::Priority p) { @@ -29,21 +31,21 @@ void TorrentBaseContext::setPriorityByFileOrder(Torrent *torrent, const QListfileCount(); - foreach (auto fileIndex, fileIndexes) { + for (auto fileIndex : fileIndexes) { auto priority = TorrentBaseContext::computePriority(fileIndex, fileCount); setPriority(torrent, fileIndex, priority); } } -TorrentFileInfo::Priority TorrentBaseContext::computePriority(int row, int count) +TorrentFileInfo::Priority TorrentBaseContext::computePriority(int row, qsizetype count) { if (count < 3) { return TorrentFileInfo::Normal; } - qreal pos = qreal(row + 1) / count; - if (pos < 0.3334) { + auto pos = static_cast(row + 1) / static_cast(count); + if (pos < ONE_THIRD) { return TorrentFileInfo::High; - } else if (pos < 0.6667) { + } else if (pos < TWO_THIRDS) { return TorrentFileInfo::Normal; } return TorrentFileInfo::Low; diff --git a/src/core/torrentbasecontext.h b/src/core/torrentbasecontext.h index 155e3481..349da6fd 100644 --- a/src/core/torrentbasecontext.h +++ b/src/core/torrentbasecontext.h @@ -30,7 +30,7 @@ class TorrentBaseContext virtual void setPriority(Torrent *torrent, int index, TorrentFileInfo::Priority p); virtual void setPriorityByFileOrder(Torrent *torrent, const QList &rows); - static TorrentFileInfo::Priority computePriority(int row, int count); + static TorrentFileInfo::Priority computePriority(int row, qsizetype count); }; #endif // CORE_TORRENT_BASE_CONTEXT_H diff --git a/src/core/torrentcontext.cpp b/src/core/torrentcontext.cpp index 8bf05688..3223b7b6 100644 --- a/src/core/torrentcontext.cpp +++ b/src/core/torrentcontext.cpp @@ -46,7 +46,7 @@ static inline QString get_setting_key(int s) if (name) { return QString::fromUtf8(name); } - return QString(); + return {}; } QString TorrentContext::upload_rate_limit() @@ -78,7 +78,8 @@ QString TorrentContext::version() QString TorrentContext::website() { - return QString("libtorrent"); + using namespace Qt::Literals::StringLiterals; + return "libtorrent"_L1; } /****************************************************************************** diff --git a/src/core/torrentcontext.h b/src/core/torrentcontext.h index bdc62b99..3b67f5a0 100644 --- a/src/core/torrentcontext.h +++ b/src/core/torrentcontext.h @@ -51,7 +51,7 @@ class TorrentContext : public QObject, public TorrentBaseContext // before deleted status private: TorrentContext(); - ~TorrentContext() Q_DECL_OVERRIDE = default; + ~TorrentContext() override = default; public: TorrentContext(TorrentContext const&) = delete; // Don't Implement void operator=(TorrentContext const&) = delete; // Don't implement @@ -77,7 +77,6 @@ class TorrentContext : public QObject, public TorrentBaseContext QList presetMinCache() const; QList presetHighPerf() const; - /* Session */ bool isEnabled() const; void setEnabled(bool enabled); @@ -93,7 +92,7 @@ class TorrentContext : public QObject, public TorrentBaseContext void resumeTorrent(Torrent *torrent); void pauseTorrent(Torrent *torrent); - void setPriority(Torrent *torrent, int index, TorrentFileInfo::Priority p) Q_DECL_OVERRIDE; + void setPriority(Torrent *torrent, int index, TorrentFileInfo::Priority p) override; signals: void changed(); diff --git a/src/core/torrentcontext_p.cpp b/src/core/torrentcontext_p.cpp index 1ea938b8..9405920a 100644 --- a/src/core/torrentcontext_p.cpp +++ b/src/core/torrentcontext_p.cpp @@ -16,7 +16,7 @@ #include "torrentcontext_p.h" -#include +#include #include #include #include @@ -68,6 +68,7 @@ #define qDebug_1 qDebug() << " + | " #define qDebug_2 qDebug() << " | + " +using namespace Qt::Literals::StringLiterals; static const lt::status_flags_t s_torrent_status_flags = lt::torrent_handle::query_distributed_copies @@ -93,19 +94,18 @@ static inline lt::download_priority_t fromPriority(const TorrentFileInfo::Priori static inline TorrentInfo::TorrentState toState(const lt::torrent_status::state_t &s); static inline lt::torrent_status::state_t fromState(const TorrentInfo::TorrentState &s); +const std::chrono::milliseconds TIMEOUT_TERMINATING( 3000 ); +const std::chrono::milliseconds TIMEOUT_REFRESH( 500); + TorrentContextPrivate::TorrentContextPrivate(TorrentContext *qq) : QObject(qq) , q(qq) - , workerThread(Q_NULLPTR) - , settings(Q_NULLPTR) - , networkManager(Q_NULLPTR) + , workerThread(new WorkerThread(this)) { qRegisterMetaType("TorrentData"); qRegisterMetaType("TorrentStatus"); - workerThread = new WorkerThread(this); - connect(workerThread, &WorkerThread::metadataUpdated, this, &TorrentContextPrivate::onMetadataUpdated); connect(workerThread, &WorkerThread::dataUpdated, this, &TorrentContextPrivate::onDataUpdated); connect(workerThread, &WorkerThread::statusUpdated, this, &TorrentContextPrivate::onStatusUpdated); @@ -120,7 +120,7 @@ TorrentContextPrivate::TorrentContextPrivate(TorrentContext *qq) TorrentContextPrivate::~TorrentContextPrivate() { workerThread->stop(); - if (!workerThread->wait(3000)) { + if (!workerThread->wait(TIMEOUT_TERMINATING.count())) { qDebug_1 << Q_FUNC_INFO << "Terminating..."; workerThread->terminate(); workerThread->wait(); @@ -136,16 +136,16 @@ void TorrentContextPrivate::onSettingsChanged() } lt::settings_pack pack = lt::default_settings(); /* = fromSettings(settings)*/ - const QMap map = settings->torrentSettings(); + auto map = settings->torrentSettings(); QMapIterator it(map); while (it.hasNext()) { it.next(); auto key = it.key(); auto value = it.value(); - int name = lt::setting_by_name(key.toUtf8().data()); + auto name = lt::setting_by_name(key.toUtf8().data()); - int type = name & lt::settings_pack::type_mask; + auto type = name & lt::settings_pack::type_mask; switch (type) { case lt::settings_pack::string_type_base: @@ -170,7 +170,7 @@ void TorrentContextPrivate::onSettingsChanged() workerThread->setSettings(pack); - bool enabled = settings->isTorrentEnabled(); + auto enabled = settings->isTorrentEnabled(); workerThread->setEnabled(enabled); } @@ -226,8 +226,8 @@ QList TorrentContextPrivate::_toPreset(const lt::settings_pa } }; - foreach (SettingClass c, cs) { - for (int index = c.begin; index < c.end; ++index) { + for (auto c : cs) { + for (auto index = c.begin; index < c.end; ++index) { // Remove non-modifiable settings and settings managed somewhere else. switch (index) { @@ -238,11 +238,11 @@ QList TorrentContextPrivate::_toPreset(const lt::settings_pa break; } - const char* name = lt::name_for_setting(index); + auto name = lt::name_for_setting(index); if (name == nullptr) { continue; } - const QString key = QString::fromUtf8(name); + auto key = QString::fromUtf8(name); if (!key.isEmpty()) { QVariant value = c.pf(all, index); TorrentSettingItem item; @@ -286,16 +286,16 @@ void TorrentContextPrivate::onStopped() void TorrentContextPrivate::onMetadataUpdated(TorrentData data) { qDebug_1 << Q_FUNC_INFO; - Torrent *torrent = find(data.unique_id); + auto torrent = find(data.unique_id); if (torrent) { torrent->setDetail(data.detail, true); torrent->setMetaInfo(data.metaInfo); // setMetaInfo will emit the GUI update signal - lt::torrent_handle handle = workerThread->findTorrent(data.unique_id); + auto handle = workerThread->findTorrent(data.unique_id); if (handle.is_valid()) { - std::shared_ptr ti = handle.torrent_file(); + auto ti = handle.torrent_file(); if (ti) { - const QString torrentFile = torrent->localFullFileName(); // destination + auto torrentFile = torrent->localFullFileName(); // destination ensureDestinationPathExists(torrent); writeTorrentFileFromMagnet(torrentFile, ti); @@ -318,7 +318,7 @@ void TorrentContextPrivate::onMetadataUpdated(TorrentData data) void TorrentContextPrivate::onDataUpdated(TorrentData data) { qDebug_1 << Q_FUNC_INFO; - Torrent *torrent = find(data.unique_id); + auto torrent = find(data.unique_id); if (torrent) { torrent->setDetail(data.detail, true); torrent->setMetaInfo(data.metaInfo); // setMetaInfo will emit the GUI update signal @@ -330,7 +330,7 @@ void TorrentContextPrivate::onDataUpdated(TorrentData data) void TorrentContextPrivate::onStatusUpdated(TorrentStatus status) { qDebug_1 << Q_FUNC_INFO; - Torrent *torrent = find(status.unique_id); + auto torrent = find(status.unique_id); if (torrent) { torrent->setInfo(status.info, false); torrent->setDetail(status.detail, false); @@ -341,9 +341,9 @@ void TorrentContextPrivate::onStatusUpdated(TorrentStatus status) ******************************************************************************/ void TorrentContextPrivate::ensureDestinationPathExists(Torrent *torrent) { - const QString path = torrent->localFullFileName(); + auto path = torrent->localFullFileName(); const QFileInfo fi(path); - const QString outputPath = fi.absolutePath(); + auto outputPath = fi.absolutePath(); QDir().mkpath(outputPath); } @@ -351,15 +351,15 @@ void TorrentContextPrivate::ensureDestinationPathExists(Torrent *torrent) ******************************************************************************/ static bool isMagnetSource(const QString &source) { - const QUrl url = QUrl::fromUserInput(source); - return url.scheme().toLower() == QLatin1String("magnet"); + auto url = QUrl::fromUserInput(source); + return url.scheme().toLower() == "magnet"_L1; } static bool isTorrentSource(const QString &source) { - const QUrl url = QUrl::fromUserInput(source); + auto url = QUrl::fromUserInput(source); QFileInfo fi(url.path()); - return fi.suffix().toLower() == QLatin1String("torrent"); + return fi.suffix().toLower() == "torrent"_L1; } static bool isLocalSource(const QString &source) @@ -372,9 +372,10 @@ static bool isDistantSource(const QString &source) return isTorrentSource(source) && !QUrl::fromUserInput(source).isLocalFile(); } -static bool isInfoHashSource(const QString &/*source*/) +static bool isInfoHashSource(const QString &source) { - return false; // TODO + Q_UNUSED(source) + return false; /// \todo implement it } static QString localSource(const QString &source) @@ -385,28 +386,28 @@ static QString localSource(const QString &source) // url can be percent-encoded or pretty-encoded or not encoded at all. // Try to figure out the correct path - const QUrl url = QUrl::fromUserInput(source); - const QString localFile = url.toLocalFile(); + auto url = QUrl::fromUserInput(source); + auto localFile = url.toLocalFile(); if (QFileInfo::exists(localFile)) { return localFile; } - const QString fromPercentEncoding = QUrl::fromPercentEncoding(source.toUtf8()); + auto fromPercentEncoding = QUrl::fromPercentEncoding(source.toUtf8()); if (QFileInfo::exists(fromPercentEncoding)) { return fromPercentEncoding; } // Url from app's argument - const QUrl url2 = QUrl::fromEncoded(source.toLocal8Bit()); + auto url2 = QUrl::fromEncoded(source.toLocal8Bit()); if (QFileInfo::exists(url2.path())) { return fromPercentEncoding; } - return QString(); + return {}; } static bool copyFile(const QString &from, const QString &to) { - const QString source = localSource(from); // eventually decode percent + auto source = localSource(from); // eventually decode percent return QFile::copy(source, to); } @@ -418,11 +419,11 @@ void TorrentContextPrivate::prepareTorrent(Torrent *torrent) if (!torrent) { return; } - TorrentInfo info = torrent->info(); + auto info = torrent->info(); info.state = TorrentInfo::downloading_metadata; torrent->setInfo(info, false); - QString torrentFile = torrent->localFullFileName(); // destination + auto torrentFile = torrent->localFullFileName(); // destination if (QFileInfo::exists(torrentFile)) { readTorrentFile(torrentFile, torrent); @@ -430,7 +431,7 @@ void TorrentContextPrivate::prepareTorrent(Torrent *torrent) } else { ensureDestinationPathExists(torrent); - const QString source = torrent->url(); + auto source = torrent->url(); if (isMagnetSource(source)) { downloadMagnetLink(torrent); @@ -465,8 +466,8 @@ void TorrentContextPrivate::stopPrepare(Torrent *torrent) ******************************************************************************/ void TorrentContextPrivate::downloadMagnetLink(Torrent *torrent) { - const QString source = torrent->url(); - const QUrl url = QUrl::fromUserInput(source); + auto source = torrent->url(); + auto url = QUrl::fromUserInput(source); qDebug_1 << Q_FUNC_INFO << url; @@ -482,8 +483,8 @@ void TorrentContextPrivate::downloadMagnetLink(Torrent *torrent) */ void TorrentContextPrivate::downloadTorrentFile(Torrent *torrent) { - const QString source = torrent->url(); - const QUrl url = QUrl::fromUserInput(source); + auto source = torrent->url(); + auto url = QUrl::fromUserInput(source); qDebug_1 << Q_FUNC_INFO << url; @@ -505,11 +506,11 @@ void TorrentContextPrivate::downloadTorrentFile(Torrent *torrent) void TorrentContextPrivate::abortNetworkReply(Torrent *torrent) { - QMapIterator it(m_currentDownloads); + QHashIterator it(m_currentDownloads); while (it.hasNext()) { it.next(); - QNetworkReply* currentReply = it.key(); - Torrent* currentTorrent = it.value(); + auto currentReply = it.key(); + auto currentTorrent = it.value(); if (currentTorrent == torrent) { currentReply->abort(); /* @@ -528,7 +529,7 @@ void TorrentContextPrivate::onNetworkReplyFinished() return; } - Torrent *torrent = Q_NULLPTR; + Torrent *torrent = nullptr; if (m_currentDownloads.contains(reply)) { torrent = m_currentDownloads.take(reply); } @@ -536,11 +537,11 @@ void TorrentContextPrivate::onNetworkReplyFinished() return; } - QUrl url = reply->url(); + auto url = reply->url(); qDebug_1 << Q_FUNC_INFO << url; if (reply->error() != QNetworkReply::NoError) { - TorrentMetaInfo m = torrent->metaInfo(); + auto m = torrent->metaInfo(); m.error.type = TorrentError::MetadataDownloadError; m.error.message = QString("%0\n\n%1\n\n%2").arg( tr("Can't download metadata."), @@ -552,7 +553,7 @@ void TorrentContextPrivate::onNetworkReplyFinished() return; } if (reply->bytesAvailable() <= 0) { - TorrentMetaInfo m = torrent->metaInfo(); + auto m = torrent->metaInfo(); m.error.type = TorrentError::MetadataDownloadError; m.error.message = tr("No metadata downloaded."); torrent->setMetaInfo(m); @@ -563,7 +564,7 @@ void TorrentContextPrivate::onNetworkReplyFinished() reply->deleteLater(); - QString torrentFile = torrent->localFullFileName(); // destination + auto torrentFile = torrent->localFullFileName(); // destination writeTorrentFile(torrentFile, reply); /* * The .torrent file is immediately loaded after being written, @@ -578,8 +579,8 @@ void TorrentContextPrivate::onNetworkReplyFinished() void TorrentContextPrivate::archiveExistingFile(const QString &filename) { if (QFileInfo::exists(filename)) { - QString archive = QString("%0.0.old").arg(filename); - int i = 0; + auto archive = QString("%0.0.old").arg(filename); + auto i = 0; while (QFileInfo::exists(archive)) { i++; archive = QString("%0.%1.old").arg(filename, QString::number(i)); @@ -602,15 +603,16 @@ void TorrentContextPrivate::writeTorrentFile(const QString &filename, QIODevice } void TorrentContextPrivate::writeTorrentFileFromMagnet( - const QString &filename, std::shared_ptr ti) + const QString &filename, + std::shared_ptr ti) { archiveExistingFile(filename); // Bittorrent Encoding lt::create_torrent ct(*ti); - lt::entry te = ct.generate(); + auto te = ct.generate(); std::vector buffer; - bencode(std::back_inserter(buffer), te); + lt::bencode(std::back_inserter(buffer), te); // Write QByteArray data(&buffer[0], static_cast(buffer.size())); @@ -640,16 +642,16 @@ void TorrentContextPrivate::readTorrentFile(const QString &filename, Torrent *to return; } - TorrentMetaInfo metaInfo = torrent->metaInfo(); + auto metaInfo = torrent->metaInfo(); metaInfo.initialMetaInfo = workerThread->dump(filename); - TorrentInfo info = torrent->info(); + auto info = torrent->info(); info.state = TorrentInfo::stopped; torrent->setInfo(info, true); torrent->setMetaInfo(metaInfo); // setMetaInfo will emit the GUI update signal // Do a fake 'detail' update, to initialize the torrent. - TorrentHandleInfo detail = torrent->detail(); + auto detail = torrent->detail(); detail.files.clear(); for (int index = 0; index < metaInfo.initialMetaInfo.files.count(); ++index) { TorrentFileInfo fi; @@ -664,8 +666,8 @@ void TorrentContextPrivate::readTorrentFile(const QString &filename, Torrent *to bool TorrentContextPrivate::hasTorrent(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - return h.is_valid(); + auto handle = find(torrent); + return handle.is_valid(); } /****************************************************************************** @@ -675,12 +677,12 @@ bool TorrentContextPrivate::hasTorrent(Torrent *torrent) */ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent { - TorrentInfo info = torrent->info(); + auto info = torrent->info(); info.state = TorrentInfo::checking_files; torrent->setInfo(info, false); - QString source = torrent->url(); - QString torrentFile = torrent->localFullFileName(); // destination + auto source = torrent->url(); + auto torrentFile = torrent->localFullFileName(); // destination if (QFileInfo::exists(torrentFile)) { source = torrentFile; @@ -689,21 +691,20 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent qDebug_1 << Q_FUNC_INFO << source; ensureDestinationPathExists(torrent); - const QString outputPath = torrent->localFilePath(); + auto outputPath = torrent->localFilePath(); lt::add_torrent_params p; if (isMagnetSource(source)) { // Add from magnet link - TorrentInfo info = torrent->info(); + auto info = torrent->info(); info.state = TorrentInfo::downloading_metadata; torrent->setInfo(info, false); - QByteArray bytes = source.toLatin1(); + auto bytes = source.toLatin1(); // QByteArray bytes = source.toUtf8(); - const char * ptr = bytes.constData(); - boost::string_view::size_type size - = static_cast(bytes.size()); + auto ptr = bytes.constData(); + auto size = static_cast(bytes.size()); lt::string_view uri { ptr, size }; lt::error_code ec; @@ -722,7 +723,7 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent } else { if (isTorrentSource(source)) { // Add from .torrent file - std::string torrent = source.toStdString(); + auto torrent = source.toStdString(); lt::error_code ec; auto ti = std::make_shared(torrent, ec); if (ec) { @@ -741,7 +742,7 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent // is the only known property of the torrent. i.e. you don't have a // .torrent file nor a magnet link. - char const* s = source.toLocal8Bit().data(); + auto s = source.toLocal8Bit().data(); lt::sha1_hash h1(s); lt::info_hash_t infohashes(h1); lt::add_torrent_params p; @@ -749,21 +750,19 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent } p.file_priorities.clear(); - for (int fi = 0; fi < torrent->fileCount(); ++fi) { + for (auto fi = 0; fi < torrent->fileCount(); ++fi) { auto priority = fromPriority(torrent->filePriority(fi)); p.file_priorities.push_back(priority); } } - p.flags &= ~lt::torrent_flags::duplicate_is_error; // do not raise exception if duplicate - p.save_path = outputPath.toStdString(); // Blocking insertion lt::error_code ec2; - lt::torrent_handle h = workerThread->addTorrent(std::move(p), ec2); + auto handle = workerThread->addTorrent(std::move(p), ec2); if (ec2) { qDebug_1 << "failed to load torrent"; qDebug_1 << QString::fromStdString(source.toStdString()); @@ -771,13 +770,13 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent return false; } - if (!h.is_valid()) { + if (!handle.is_valid()) { return false; } - h.pause(); + handle.pause(); - const UniqueId uuid = WorkerThread::toUniqueId(h.info_hash()); + auto uuid = WorkerThread::toUniqueId(handle.info_hash()); hashMap.insert(uuid, torrent); return true; } @@ -787,10 +786,10 @@ bool TorrentContextPrivate::addTorrent(Torrent *torrent) // resumeTorrent void TorrentContextPrivate::removeTorrent(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - workerThread->removeTorrent(h); // needs calling lt::session - const UniqueId uuid = WorkerThread::toUniqueId(h.info_hash()); + auto handle = find(torrent); + if (handle.is_valid()) { + workerThread->removeTorrent(handle); // needs calling lt::session + auto uuid = WorkerThread::toUniqueId(handle.info_hash()); hashMap.remove(uuid); } } @@ -800,18 +799,18 @@ void TorrentContextPrivate::removeTorrent(Torrent *torrent) void TorrentContextPrivate::resumeTorrent(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.resume(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.resume(); } } void TorrentContextPrivate::pauseTorrent(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.pause(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.pause(); } } @@ -820,36 +819,36 @@ void TorrentContextPrivate::pauseTorrent(Torrent *torrent) void TorrentContextPrivate::moveQueueUp(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.queue_position_up(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.queue_position_up(); } } void TorrentContextPrivate::moveQueueDown(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.queue_position_down(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.queue_position_down(); } } void TorrentContextPrivate::moveQueueTop(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.queue_position_top(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.queue_position_top(); } } void TorrentContextPrivate::moveQueueBottom(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.queue_position_bottom(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.queue_position_bottom(); } } @@ -859,11 +858,11 @@ void TorrentContextPrivate::changeFilePriority(Torrent *torrent, int index, TorrentFileInfo::Priority p) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - lt::file_index_t findex = static_cast(index); - lt::download_priority_t priority = fromPriority(p); - h.file_priority(findex, priority); + auto handle = find(torrent); + if (handle.is_valid()) { + auto findex = static_cast(index); + auto priority = fromPriority(p); + handle.file_priority(findex, priority); } } @@ -872,12 +871,12 @@ void TorrentContextPrivate::changeFilePriority(Torrent *torrent, void TorrentContextPrivate::addSeed(Torrent *torrent, const TorrentWebSeedMetaInfo &seed) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { + auto handle = find(torrent); + if (handle.is_valid()) { if (seed.type == TorrentWebSeedMetaInfo::Type::UrlSeed) { - h.add_url_seed(seed.url.toStdString()); + handle.add_url_seed(seed.url.toStdString()); } else { - h.add_http_seed(seed.url.toStdString()); + handle.add_http_seed(seed.url.toStdString()); } } } @@ -885,12 +884,12 @@ void TorrentContextPrivate::addSeed(Torrent *torrent, const TorrentWebSeedMetaIn void TorrentContextPrivate::removeSeed(Torrent *torrent, const TorrentWebSeedMetaInfo &seed) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { + auto handle = find(torrent); + if (handle.is_valid()) { if (seed.type == TorrentWebSeedMetaInfo::Type::UrlSeed) { - h.remove_url_seed(seed.url.toStdString()); + handle.remove_url_seed(seed.url.toStdString()); } else { - h.remove_http_seed(seed.url.toStdString()); + handle.remove_http_seed(seed.url.toStdString()); } } } @@ -898,19 +897,18 @@ void TorrentContextPrivate::removeSeed(Torrent *torrent, const TorrentWebSeedMet void TorrentContextPrivate::removeAllSeeds(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { + auto handle = find(torrent); + if (handle.is_valid()) { std::set::iterator i, end; - std::set seeds; - seeds = h.url_seeds(); - for (i = seeds.begin(), end = (seeds.end()); i != end; ++i) { - h.remove_url_seed(*i); + auto url_seeds = handle.url_seeds(); + for (i = url_seeds.begin(), end = (url_seeds.end()); i != end; ++i) { + handle.remove_url_seed(*i); } - seeds = h.http_seeds(); - for (i = seeds.begin(), end = (seeds.end()); i != end; ++i) { - h.remove_http_seed(*i); + auto http_seeds = handle.http_seeds(); + for (i = http_seeds.begin(), end = (http_seeds.end()); i != end; ++i) { + handle.remove_http_seed(*i); } } } @@ -920,23 +918,22 @@ void TorrentContextPrivate::removeAllSeeds(Torrent *torrent) void TorrentContextPrivate::addPeer(Torrent *torrent, const TorrentPeerInfo &peer) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - lt::tcp::endpoint endpoint = fromEndPoint(peer.endpoint); - h.connect_peer(endpoint); + auto handle = find(torrent); + if (handle.is_valid()) { + auto endpoint = fromEndPoint(peer.endpoint); + handle.connect_peer(endpoint); } } /****************************************************************************** ******************************************************************************/ -void TorrentContextPrivate::addTracker(Torrent *torrent, - const TorrentTrackerInfo &tracker) +void TorrentContextPrivate::addTracker(Torrent *torrent, const TorrentTrackerInfo &tracker) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - lt::announce_entry entry = fromTorrentTrackerInfo(tracker); - h.add_tracker(entry); + auto handle = find(torrent); + if (handle.is_valid()) { + auto entry = fromTorrentTrackerInfo(tracker); + handle.add_tracker(entry); } } @@ -955,27 +952,27 @@ void TorrentContextPrivate::removeTracker(Torrent *torrent, void TorrentContextPrivate::forceRecheck(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.force_recheck(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.force_recheck(); } } void TorrentContextPrivate::forceReannounce(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.force_reannounce(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.force_reannounce(); } } void TorrentContextPrivate::forceDHTReannounce(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.force_dht_announce(); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.force_dht_announce(); } } @@ -994,9 +991,9 @@ void TorrentContextPrivate::setSSLCertificatePath(Torrent *torrent, const QStrin void TorrentContextPrivate::scrapeTracker(Torrent *torrent, int index) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.scrape_tracker(index); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.scrape_tracker(index); } } @@ -1005,18 +1002,18 @@ void TorrentContextPrivate::scrapeTracker(Torrent *torrent, int index) void TorrentContextPrivate::setUploadBandwidth(Torrent *torrent, int limit) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.set_upload_limit(limit); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.set_upload_limit(limit); } } void TorrentContextPrivate::setDownloadBandwidth(Torrent *torrent, int limit) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.set_download_limit(limit); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.set_download_limit(limit); } } @@ -1025,18 +1022,18 @@ void TorrentContextPrivate::setDownloadBandwidth(Torrent *torrent, int limit) void TorrentContextPrivate::setMaxUploads(Torrent *torrent, int limit) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.set_max_uploads(limit); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.set_max_uploads(limit); } } void TorrentContextPrivate::setMaxConnections(Torrent *torrent, int limit) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - h.set_max_connections(limit); + auto handle = find(torrent); + if (handle.is_valid()) { + handle.set_max_connections(limit); } } @@ -1045,10 +1042,10 @@ void TorrentContextPrivate::setMaxConnections(Torrent *torrent, int limit) void TorrentContextPrivate::renameFile(Torrent *torrent, int index, const QString &newName) { qDebug_1 << Q_FUNC_INFO; - lt::torrent_handle h = find(torrent); - if (h.is_valid()) { - lt::file_index_t findex = static_cast(index); - h.rename_file(findex, newName.toStdString()); + auto handle = find(torrent); + if (handle.is_valid()) { + auto findex = static_cast(index); + handle.rename_file(findex, newName.toStdString()); } } @@ -1063,7 +1060,7 @@ inline Torrent* TorrentContextPrivate::find(const UniqueId &uuid) inline lt::torrent_handle TorrentContextPrivate::find(Torrent *torrent) { qDebug_1 << Q_FUNC_INFO; - const UniqueId info_hash = hashMap.key(torrent, UniqueId()); + auto info_hash = hashMap.key(torrent, UniqueId()); return workerThread->findTorrent(info_hash); // return hashMap.key(item, lt::torrent_handle()); } @@ -1071,8 +1068,8 @@ inline lt::torrent_handle TorrentContextPrivate::find(Torrent *torrent) /****************************************************************************** ******************************************************************************/ WorkerThread::WorkerThread(QObject *parent) : QThread(parent) + , m_session_ptr(new lt::session()) { - m_session_ptr = new lt::session(); } /****************************************************************************** @@ -1138,7 +1135,7 @@ static std::vector load_file(std::string const& filename) in.exceptions(std::ifstream::failbit); in.open(filename.c_str(), std::ios_base::in | std::ios_base::binary); in.seekg(0, std::ios_base::end); - qsizetype const size = static_cast(in.tellg()); + auto size = static_cast(in.tellg()); in.seekg(0, std::ios_base::beg); std::vector ret(size); in.read(ret.data(), static_cast(size)); @@ -1147,18 +1144,20 @@ static std::vector load_file(std::string const& filename) TorrentInitialMetaInfo WorkerThread::dump(const QString &filename) const { - std::vector buf = load_file(filename.toStdString()); + auto buf = load_file(filename.toStdString()); lt::error_code ec; int pos = -1; lt::load_torrent_limits cfg; - lt::bdecode_node const e = lt::bdecode(buf, ec, &pos, - cfg.max_decode_depth, - cfg.max_decode_tokens); + //lt::bdecode_node const e = lt::bdecode( + auto e = lt::bdecode( + buf, ec, &pos, + cfg.max_decode_depth, + cfg.max_decode_tokens); if (ec) { qDebug_2 << "failed to decode: '" << QString::fromStdString(ec.message()) << "' at character: " << pos; - return TorrentInitialMetaInfo(); + return {}; } lt::torrent_info const t(std::move(e), cfg); std::shared_ptr ti = std::make_shared(t); @@ -1173,7 +1172,7 @@ UniqueId WorkerThread::toUniqueId(const lt::sha1_hash &hash) auto hex = lt::aux::to_hex(hash); return QString::fromStdString(hex).toUpper(); } - return QString(); + return {}; } lt::sha1_hash WorkerThread::fromUniqueId(const UniqueId &uuid) @@ -1197,7 +1196,7 @@ lt::torrent_handle WorkerThread::addTorrent(lt::add_torrent_params const& params if (m_session_ptr && m_session_ptr->is_valid()) { return m_session_ptr->add_torrent(params, ec); } - return lt::torrent_handle(); + return {}; } /****************************************************************************** @@ -1279,7 +1278,7 @@ void WorkerThread::run() session.post_session_stats(); session.post_dht_stats(); - QThread::msleep(500); + QThread::msleep(TIMEOUT_REFRESH.count()); std::vector alerts; session.pop_alerts(&alerts); @@ -1313,223 +1312,223 @@ void WorkerThread::run() void WorkerThread::signalizeAlert(lt::alert* a) { /* status_notification */ - if (lt::torrent_removed_alert* s = lt::alert_cast(a)) { + if (auto s = lt::alert_cast(a)) { //QString hash = toString(s->info_hashes.get_best()); // emit torrentRemoved(hash); log(s); } - else if (lt::state_changed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // lt::torrent_status::state_t oldStatus = s->prev_state; // lt::torrent_status::state_t newStatus = s->state; // emit torrentStateChanged(oldState, newState); // rem quel torrent ? log(s); } - else if (lt::hash_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int piece_index = (int)s->piece_index; // emit pieceHashCheckFailed(piece_index); log(s); } - else if (lt::torrent_finished_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentFinished(); log(s); } - else if (lt::torrent_paused_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentPaused(); log(s); } - else if (lt::torrent_resumed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentResumed(); log(s); } - else if (lt::torrent_checked_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentChecked(); log(s); } - else if (lt::fastresume_rejected_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentFastResumeFailed(); log(s); } - else if (lt::trackerid_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit trackeridReceived(); log(s); } - else if (lt::torrent_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentError(); log(s); } - else if (lt::torrent_need_cert_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit torrentSSLError(); log(s); } - else if (lt::add_torrent_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { log(s); onTorrentAdded(s->handle, s->params, s->error); } - else if (lt::state_update_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { /* Note: This alert is emitted very often (each loop) */ // log(s); onStateUpdated(s->status); } // magnet extension - else if (lt::metadata_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // emit metadataFailed(); log(s); } - else if (lt::metadata_received_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { log(s); onMetadataReceived(s->handle); } // IP - else if (lt::external_ip_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit externalIpAddressReceived(); } - else if (lt::peer_blocked_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerIpBlocked(); } // dht - else if (lt::dht_announce_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHT(); } - else if (lt::dht_get_peers_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTReceviedd(); } - else if (lt::dht_bootstrap_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTbootstrapDone(); } - else if (lt::dht_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTError(); } - else if (lt::dht_immutable_item_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTImmmutablee(); } - else if (lt::dht_mutable_item_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTmutablee(); } - else if (lt::dht_put_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerDHTput(); } - else if (lt::i2p_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit i2pError(); } - else if (lt::dht_outgoing_get_peers_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_get_peers_Sent(); } // Firewall error ? - else if (lt::udp_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit protocolError(); } - else if (lt::listen_succeeded_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit hostPortOpened(); } - else if (lt::listen_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit hostPortOpenFailed(); } - else if (lt::portmap_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit portOpened(); } - else if (lt::portmap_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit portOpenFailed(); } - else if (lt::portmap_log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugPort(); } - else if (lt::log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugLog(); } - else if (lt::torrent_log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugTorrentLog(); } - else if (lt::peer_log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugPeerLog(); } - else if (lt::lsd_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugLSDPeerLog(); } - else if (lt::dht_log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugDHTLog(); } - else if (lt::dht_pkt_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_pkt_alert(); } - else if (lt::dht_get_peers_reply_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_get_peers_reply_alert(); } - else if (lt::dht_direct_response_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_direct_response_alert(); } - else if (lt::picker_log_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit debugPickerLog(); } - else if (lt::session_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit session_error_alert(); } - else if (lt::dht_live_nodes_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_live_nodes_alert(); } - else if (lt::dht_sample_infohashes_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dht_sample_infohashes_alert(); } /* stats_notification */ - else if (lt::session_stats_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // const lt::span counters = s->counters() ; // TODO Q_UNUSED(s) // emit sessionStatsUpdated(); } - else if (lt::dht_stats_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit dhtStatsUpdated(); } - else if (lt::session_stats_header_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit session_stats_header_Updated(); } /* storage_notification */ - // else if (lt::read_piece_alert* s = lt::alert_cast(a)) { + // else if (auto s = lt::alert_cast(a)) { // emit fileCompleted(index); // } - else if (lt::file_renamed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int index = (int)s->index; // QString newName = QString::fromUtf8(s->new_name()); Q_UNUSED(s) // emit fileRenamed(index, newName); } - else if (lt::file_rename_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int index = (int)s->index; // QString errorMessage = QString::fromStdString(s->error.message()); Q_UNUSED(s) // emit fileRenameFailed(index, errorMessage); } - else if (lt::storage_moved_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit storageMoved(); } - else if (lt::storage_moved_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit storageMoveFailed(); } - else if (lt::torrent_deleted_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit torrentDeleted(); } - else if (lt::torrent_delete_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit torrentDeleteFailed(); } - else if (lt::save_resume_data_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit resumeDataSaved(); - } else if (lt::save_resume_data_failed_alert* s = lt::alert_cast(a)) { + } else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit resumeDataSaveFailed(); } - else if (lt::file_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit fileReadOrWriteError(); } - else if (lt::cache_flushed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit cache_flushed(); } @@ -1537,129 +1536,129 @@ void WorkerThread::signalizeAlert(lt::alert* a) /* file_progress_notification */ - else if (lt::file_completed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int index = (int)s->index; Q_UNUSED(s) // emit fileCompleted(index); } /* performance_warning */ - else if (lt::performance_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // QString message = QString::fromStdString(s->message()); Q_UNUSED(s) // emit performanceWarning(message); } /* tracker_notification & error_notification */ - else if (lt::tracker_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int times_in_row = s->times_in_row; Q_UNUSED(s) // emit trackerConnectionFailed(times_in_row, errorCode); } - else if (lt::tracker_warning_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // QString message = QString::fromUtf8(s->warning_message()); Q_UNUSED(s) // emit trackerMessageReceived(message); } - else if (lt::scrape_reply_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int incomplete = s->incomplete; // int complete = s->complete; Q_UNUSED(s) // emit trackerScrapeSucceeded(incomplete, complete); } - else if (lt::scrape_failed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // QString errorCode = QString::fromStdString(s->error.message()); // QString errorMessage = QString::fromUtf8(s->error_message()); Q_UNUSED(s) // emit trackerScrapeFailed(errorCode, errorMessage); } - else if (lt::tracker_reply_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int peersCount = s->num_peers; Q_UNUSED(s) // emit trackerInfo(peersCount); } - else if (lt::dht_reply_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int peersCount = s->num_peers; Q_UNUSED(s) // emit trackerDHTInfo(peersCount); } - else if (lt::tracker_announce_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int eventcode = s->event; Q_UNUSED(s) // emit trackerEventSent(eventcode); } /* peer_notification */ - else if (lt::peer_ban_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerBanned(); } - else if (lt::peer_unsnubbed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerUnsnubbed(); } - else if (lt::peer_snubbed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerSnubbed(); } - else if (lt::peer_error_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // QString operation = QString::fromUtf8(lt::operation_name(s->op)); // QString errorCode = QString::fromStdString(s->error.message()); Q_UNUSED(s) // emit peerAboutToDisconnected(operation, errorCode); } - else if (lt::peer_connect_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // don't log every peer we try to connect to return; // int socket_type = s->socket_type; // emit peerConnected(socket_type); } - else if (lt::peer_disconnected_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // int socket_type = s->socket_type; // operation_t const op; // error_code const error; // close_reason_t const reason; Q_UNUSED(s) // emit peerDisconnected(/*socket_type*/); } - else if (lt::invalid_request_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { // peer_request const request; // bool const we_have; // bool const peer_interested; // bool const withheld; Q_UNUSED(s) // emit peerInvalidPieceReceived(); } - else if (lt::piece_finished_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit pieceFinished(); } - else if (lt::lsd_peer_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit lsd_peer(); } - else if (lt::incoming_connection_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerIncomingConnectionAccepted(); } - else if (lt::incoming_request_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerIncomingrequestAccepted(); } /* block_progress_notification */ - else if (lt::request_dropped_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerPieceRejected(); } - else if (lt::block_timeout_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerPieceTimeOut(); } - else if (lt::block_finished_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerPieceFinished(); } - else if (lt::block_downloading_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerPieceDownloading(); } - else if (lt::unwanted_block_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit peerPieceUnwanted(); } - else if (lt::url_seed_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit seedUrlFailed(); } - else if (lt::block_uploaded_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit blockUploaded(); } /* block_progress_notification */ - else if (lt::alerts_dropped_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit alerts_dropped_alert(); } - else if (lt::socks5_alert* s = lt::alert_cast(a)) { + else if (auto s = lt::alert_cast(a)) { Q_UNUSED(s) // emit socks5_alert(); } @@ -1710,9 +1709,9 @@ inline void WorkerThread::onMetadataReceived(const lt::torrent_handle &handle) // set all the files priority to zero, to not download them if (handle.torrent_file()) { - int fileCount = handle.torrent_file()->num_files(); - for (int i = 0; i < fileCount; i++) { - lt::file_index_t findex = static_cast(i); + auto fileCount = handle.torrent_file()->num_files(); + for (auto i = 0; i < fileCount; i++) { + auto findex = static_cast(i); handle.file_priority(findex, lt::dont_download); } } @@ -1735,7 +1734,7 @@ inline void WorkerThread::onMetadataReceived(const lt::torrent_handle &handle) ******************************************************************************/ inline void WorkerThread::onStateUpdated(const std::vector &status) { - foreach (const lt::torrent_status &s, status) { + for (auto s : status) { signalizeStatusUpdated(s); } } @@ -1753,7 +1752,7 @@ inline void WorkerThread::signalizeDataUpdated(const lt::torrent_handle &handle, d.unique_id = toUniqueId(handle.info_hash()); d.detail = toTorrentHandleInfo(handle); - std::shared_ptr ti = params.ti; + auto ti = params.ti; if (!ti || !ti->is_valid()) { // it's a magnet link perhaps, metadata has not have been received yet d.metaInfo.error = TorrentError(TorrentError::NoInfoYetError); @@ -1768,7 +1767,7 @@ inline void WorkerThread::signalizeDataUpdated(const lt::torrent_handle &handle, inline void WorkerThread::signalizeStatusUpdated(const lt::torrent_status &status) { qDebug_2 << Q_FUNC_INFO; - lt::torrent_handle handle = status.handle; + auto handle = status.handle; if (!handle.is_valid()) { return; } @@ -1915,18 +1914,18 @@ inline TorrentInitialMetaInfo WorkerThread::toTorrentInitialMetaInfo(std::shared m.comment = toString(ti->comment()); m.magnetLink = toString(lt::make_magnet_uri(*ti)); - for (const std::pair &node : ti->nodes()) { + for (auto node : ti->nodes()) { m.nodes.append( TorrentNodeInfo(toString(node.first), node.second) ); } //m.bytesMetaData = ti->metadata_size(); - const lt::file_storage files = ti->files(); - for (const lt::file_index_t index : files.file_range()) { + auto files = ti->files(); + for (auto index : files.file_range()) { TorrentFileMetaInfo f; - lt::file_flags_t flags = files.file_flags(index); + auto flags = files.file_flags(index); if (flags & lt::file_storage::flag_pad_file) f.setFlag(TorrentFileMetaInfo::Flag::PadFile); if (flags & lt::file_storage::flag_hidden) f.setFlag(TorrentFileMetaInfo::Flag::Hidden); if (flags & lt::file_storage::flag_executable) f.setFlag(TorrentFileMetaInfo::Flag::Executable); @@ -1950,24 +1949,24 @@ inline TorrentInitialMetaInfo WorkerThread::toTorrentInitialMetaInfo(std::shared } - for (const lt::announce_entry &tracker : ti->trackers()) { - TorrentTrackerInfo t = toTorrentTrackerInfo(tracker); + for (auto tracker : ti->trackers()) { + auto t = toTorrentTrackerInfo(tracker); m.trackers.append(t); } - for (const lt::sha1_hash &similar_torrent : ti->similar_torrents()) { + for (auto similar_torrent : ti->similar_torrents()) { m.similarTorrents.append(toString(similar_torrent)); } - for (const std::string &collection : ti->collections()) { + for (auto collection : ti->collections()) { m.collections.append(toString(collection)); } - for (const lt::web_seed_entry &web_seed : ti->web_seeds()) { + for (auto web_seed : ti->web_seeds()) { TorrentWebSeedMetaInfo w; w.url = toString(web_seed.url); w.auth = toString(web_seed.auth); - for (const std::pair &extra_header : web_seed.extra_headers) { + for (auto extra_header : web_seed.extra_headers) { w.extraHeaders.append( QPair( toString(extra_header.first), @@ -2009,7 +2008,7 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han std::vector progress; handle.file_progress(progress, lt::torrent_handle::piece_granularity); - std::vector priorities = handle.get_file_priorities(); + auto priorities = handle.get_file_priorities(); // const std::vector file_status = handle.file_status(); @@ -2020,8 +2019,8 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han static_cast(progress.size()), static_cast(priorities.size()) }); - for (qsizetype index = 0; index < count; ++index) { - lt::file_index_t findex = static_cast(index); + for (auto index = 0; index < count; ++index) { + auto findex = static_cast(index); TorrentFileInfo fi; fi.bytesReceived = static_cast(progress.at(static_cast(index))); fi.priority = toPriority(handle.file_priority(findex)); @@ -2034,11 +2033,11 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han // *************** std::vector peers; handle.get_peer_info(peers); - for (const lt::peer_info &peer : peers) { + for (auto peer : peers) { TorrentPeerInfo d; - QString peerIp = toString(peer.ip.address().to_string()); - int peerPort = peer.ip.port(); + auto peerIp = toString(peer.ip.address().to_string()); + auto peerPort = peer.ip.port(); d.endpoint = EndPoint(peerIp, peerPort); d.userAgent = toString(peer.client); @@ -2051,7 +2050,7 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han d.lastTimeActive = peer.last_active.count(); d.timeDownloadQueue = peer.download_queue_time.count(); - lt::peer_flags_t flags = peer.flags; + auto flags = peer.flags; if (flags & lt::peer_info::interesting) d.setFlag(TorrentPeerInfo::Flag::Interesting); if (flags & lt::peer_info::choked) d.setFlag(TorrentPeerInfo::Flag::Choked); if (flags & lt::peer_info::remote_interested) d.setFlag(TorrentPeerInfo::Flag::RemoteInterested); @@ -2074,7 +2073,7 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han if (flags & lt::peer_info::rc4_encrypted) d.setFlag(TorrentPeerInfo::Flag::Rc4Encrypted); if (flags & lt::peer_info::plaintext_encrypted) d.setFlag(TorrentPeerInfo::Flag::Plaintextencrypted); - lt::peer_source_flags_t sourceFlags = peer.source; + auto sourceFlags = peer.source; if (sourceFlags & lt::peer_info::tracker) d.setSourceFlag(TorrentPeerInfo::SourceFlag::FromTracker); if (sourceFlags & lt::peer_info::dht) d.setSourceFlag(TorrentPeerInfo::SourceFlag::FromDHT); if (sourceFlags & lt::peer_info::pex) d.setSourceFlag(TorrentPeerInfo::SourceFlag::FromPeerExchange); @@ -2088,19 +2087,19 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han // *************** // Trackers // *************** - std::vector trackers = handle.trackers(); - for (const lt::announce_entry &tracker : trackers) { - TorrentTrackerInfo ti = toTorrentTrackerInfo(tracker); + auto trackers = handle.trackers(); + for (auto tracker : trackers) { + auto ti = toTorrentTrackerInfo(tracker); t.trackers.append(ti); } // *************** // Seeds // *************** - for (const std::string &webSeed : handle.http_seeds()) { + for (auto webSeed : handle.http_seeds()) { t.httpSeeds.append(toString(webSeed)); } - for (const std::string &webSeed : handle.url_seeds()) { + for (auto webSeed : handle.url_seeds()) { t.urlSeeds.append(toString(webSeed)); } @@ -2120,9 +2119,9 @@ inline TorrentHandleInfo WorkerThread::toTorrentHandleInfo(const lt::torrent_han } { - const std::vector &priorities = handle.get_piece_priorities(); + auto priorities = handle.get_piece_priorities(); QVector newPiecePriority; - foreach (const lt::download_priority_t &priority, priorities) { + for (auto priority : priorities) { newPiecePriority.append(toPriority(priority)); } t.piecePriority.swap(newPiecePriority); @@ -2137,16 +2136,16 @@ inline TorrentMetaInfo WorkerThread::toTorrentMetaInfo(const lt::add_torrent_par { TorrentMetaInfo m; - std::shared_ptr ti = params.ti; + auto ti = params.ti; m.initialMetaInfo = toTorrentInitialMetaInfo(ti); - for (const std::string &tracker : params.trackers) { + for (auto tracker : params.trackers) { m.trackers2.append(toString(tracker)); } // for (const int tracker_tier : params.tracker_tiers) { // ? // } - for (const std::pair &dht_node : params.dht_nodes) { + for (auto dht_node : params.dht_nodes) { m.dhtNodes.append( TorrentNodeInfo(toString(dht_node.first), dht_node.second) ); } @@ -2155,7 +2154,7 @@ inline TorrentMetaInfo WorkerThread::toTorrentMetaInfo(const lt::add_torrent_par } m.outputPath = toString(params.save_path); - // for (const lt::download_priority_t &file_priority : params.file_priorities) { + // for (const lt : :download_priority_t &file_priority : params.file_priorities) { // ? // } @@ -2188,21 +2187,21 @@ inline TorrentMetaInfo WorkerThread::toTorrentMetaInfo(const lt::add_torrent_par m.peersInSwarm = params.num_incomplete; m.downloadsInSwarm = params.num_downloaded; - for (const std::string &http_seed : params.http_seeds) { // todo unify http et url + for (auto http_seed : params.http_seeds) { // todo unify http et url m.httpSeeds.append(toString(http_seed)); } - for (const std::string &url_seed : params.url_seeds) { + for (auto url_seed : params.url_seeds) { m.urlSeeds.append(toString(url_seed)); } - for (const lt::tcp::endpoint &peer : params.peers) { + for (auto peer : params.peers) { TorrentPeerInfo p(toEndPoint(peer), QString()); m.defaultPeers.append(p); } - for (const lt::tcp::endpoint &banned_peer : params.banned_peers) { + for (auto banned_peer : params.banned_peers) { TorrentPeerInfo p(toEndPoint(banned_peer), QString()); m.bannedPeers.append(p); } @@ -2237,7 +2236,7 @@ inline QString WorkerThread::toString(const lt::sha1_hash &hash) const auto hex = lt::aux::to_hex(hash); return QString::fromStdString(hex).toUpper(); } - return QString(); + return {}; } /****************************************************************************** @@ -2246,7 +2245,7 @@ QBitArray WorkerThread::toBitArray(const lt::typed_bitfield & { auto size = vec.size(); QBitArray ba(size, false); - for (int i = 0; i < size; ++i) { + for (auto i = 0; i < size; ++i) { if (vec.get_bit(static_cast(i))) { ba.setBit(i); } @@ -2258,14 +2257,14 @@ QBitArray WorkerThread::toBitArray(const std::map indexes; - for (const auto &kv : map) { - const lt::piece_index_t &key = kv.first; + for (auto kv : map) { + auto key = kv.first; auto index = static_cast(key); indexes.append(index); size = qMax(size, index); } QBitArray ba(size, false); - foreach (auto index, indexes) { + for (auto index : indexes) { ba.setBit(index); } return ba; @@ -2275,10 +2274,11 @@ QBitArray WorkerThread::toBitArray(const std::map(time); - return sec > 0 - ? QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC).addSecs(sec) - : QDateTime(); + auto sec = static_cast(time); + if (sec > 0) { + return QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC).addSecs(sec); + } + return {}; } @@ -2322,7 +2322,7 @@ static inline TorrentError toTorrentError(const lt::error_code &errc, const lt:: TorrentError error; bool hasError = (static_cast(errc.value()) != 0); if (!hasError) { - error = TorrentError(); + error = {}; } else { error.message = QString::fromStdString(errc.message()); @@ -2360,7 +2360,7 @@ static inline TorrentTrackerInfo toTorrentTrackerInfo(const lt::announce_entry & { TorrentTrackerInfo t(QString::fromStdString(tracker.url)); t.trackerId = QString::fromStdString(tracker.trackerid); - for (const lt::announce_endpoint &endpoint : tracker.endpoints) { + for (auto endpoint : tracker.endpoints) { EndPoint e = toEndPoint(endpoint.local_endpoint); t.endpoints.append(e); } diff --git a/src/core/torrentcontext_p.h b/src/core/torrentcontext_p.h index 7f964970..3aecf9ff 100644 --- a/src/core/torrentcontext_p.h +++ b/src/core/torrentcontext_p.h @@ -48,8 +48,8 @@ class TorrentContextPrivate : public QObject Q_OBJECT public: - explicit TorrentContextPrivate(TorrentContext *qq = Q_NULLPTR); - ~TorrentContextPrivate() Q_DECL_OVERRIDE; + explicit TorrentContextPrivate(TorrentContext *qq = nullptr); + ~TorrentContextPrivate() override; QList allSettingsKeysAndValues() const; QList presetDefault() const; @@ -106,10 +106,10 @@ public slots: void onStatusUpdated(TorrentStatus status); public: - TorrentContext *q; - WorkerThread *workerThread; - Settings *settings; - NetworkManager *networkManager; + TorrentContext *q = nullptr; + WorkerThread *workerThread = nullptr; + Settings *settings = nullptr; + NetworkManager *networkManager = nullptr; QHash hashMap; inline Torrent *find(const UniqueId &uuid); @@ -117,8 +117,9 @@ public slots: private slots: void onNetworkReplyFinished(); + private: - QMap m_currentDownloads; + QHash m_currentDownloads; void downloadMagnetLink(Torrent *torrent); void downloadTorrentFile(Torrent *torrent); void abortNetworkReply(Torrent *torrent); @@ -144,7 +145,7 @@ class WorkerThread : public QThread public: WorkerThread(QObject *parent = nullptr); - void run() Q_DECL_OVERRIDE; + void run() override; void stop(); lt::settings_pack settings() const; @@ -179,29 +180,20 @@ class WorkerThread : public QThread void signalizeAlert(lt::alert* alert); - - inline void onTorrentAdded(const lt::torrent_handle &handle, - const lt::add_torrent_params ¶ms, - const lt::error_code &error); + inline void onTorrentAdded(const lt::torrent_handle &handle, const lt::add_torrent_params ¶ms, const lt::error_code &error); inline void onMetadataReceived(const lt::torrent_handle &handle); inline void onStateUpdated(const std::vector &status); - - inline void signalizeDataUpdated(const lt::torrent_handle &handle, - const lt::add_torrent_params ¶ms); + inline void signalizeDataUpdated(const lt::torrent_handle &handle, const lt::add_torrent_params ¶ms); inline void signalizeStatusUpdated(const lt::torrent_status &status); - inline TorrentInitialMetaInfo toTorrentInitialMetaInfo(std::shared_ptr ti) const; inline TorrentMetaInfo toTorrentMetaInfo(const lt::add_torrent_params ¶ms) const; inline TorrentHandleInfo toTorrentHandleInfo(const lt::torrent_handle &handle) const; - inline QString toString(const std::string &str) const; inline QString toString(const lt::string_view &s) const; - inline QString toString(const lt::sha1_hash &hash) const; - inline QDateTime toDateTime(const std::time_t &time) const; inline void log(lt::alert *s); diff --git a/src/core/torrentmessage.h b/src/core/torrentmessage.h index c42fbdda..91e5da83 100644 --- a/src/core/torrentmessage.h +++ b/src/core/torrentmessage.h @@ -57,11 +57,7 @@ static const QString s_unlocked = QString::fromUtf8("\xf0\x9f\x94\x93"); // 🔓 template static inline void _q_set_flag(QFlags *f, Enum flag, bool on = true) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) (*f).setFlag(flag, on); -#else - on ? (*f |= flag) : (*f &= ~flag); -#endif } @@ -97,11 +93,11 @@ class TorrentError TorrentError() = default; explicit TorrentError(Type _type, int _fileIndex = -1) - : type(_type), fileIndex(_fileIndex), message(QString()) {} + : type(_type), fileIndex(_fileIndex) {} - Type type{NoError}; - int fileIndex{-1}; - QString message; + Type type = NoError; + int fileIndex = -1; + QString message = {}; }; /****************************************************************************** @@ -459,8 +455,8 @@ class TorrentTrackerInfo TorrentTrackerInfo(const QString &_url) : url(_url) {} - QString url; - QString trackerId; // '&trackerid=' argument passed to the tracker + QString url = {}; + QString trackerId = {}; // '&trackerid=' argument passed to the tracker QList endpoints; // local listen socket (endpoint) announced to the tracker @@ -535,11 +531,11 @@ class TorrentInfo // TorrentStatusInfo Q_UNREACHABLE(); } - TorrentError error; + TorrentError error = {}; - TorrentState state{stopped}; + TorrentState state = stopped; - QString lastWorkingTrackerUrl; + QString lastWorkingTrackerUrl = {}; qsizetype bytesSessionDownloaded = 0; qsizetype bytesSessionUploaded = 0; @@ -550,8 +546,8 @@ class TorrentInfo // TorrentStatusInfo qsizetype bytesFailed = 0; qsizetype bytesRedundant = 0; - QBitArray downloadedPieces; - QBitArray verifiedPieces; // seed mode only + QBitArray downloadedPieces = {}; + QBitArray verifiedPieces = {}; // seed mode only qsizetype bytesReceived = 0; qsizetype bytesTotal = 0; @@ -562,9 +558,9 @@ class TorrentInfo // TorrentStatusInfo qsizetype bytesAllSessionsPayloadDownload = 0; qsizetype bytesAllSessionsPayloadUpload = 0; - QDateTime addedTime; /// \todo maybe it's duplicate? - QDateTime completedTime; - QDateTime lastSeenCompletedTime; + QDateTime addedTime = {}; /// \todo maybe it's duplicate? + QDateTime completedTime = {}; + QDateTime lastSeenCompletedTime = {}; qreal percent = 0; // between 0 and 100 @@ -574,8 +570,8 @@ class TorrentInfo // TorrentStatusInfo int download_payload_rate = 0; // better speed to calc the ETAs int upload_payload_rate = 0; - QTime elapsedTime; /// \todo ETA - QTime remaingTime; /// \todo ETA + QTime elapsedTime = {}; /// \todo ETA + QTime remaingTime = {}; /// \todo ETA int connectedSeedsCount = 0; int connectedPeersCount = 0; @@ -617,16 +613,14 @@ class TorrentInfo // TorrentStatusInfo bool isAnnouncingToLSD = false; bool isAnnouncingToDHT = false; - QString infohash; - + QString infohash = {}; qint64 activeTimeDuration = 0; // in seconds qint64 finishedTimeDuration = 0; /// \todo duplicate? qint64 seedingTimeDuration = 0; - QDateTime lastTimeDownload; /// \todo duplicate? - QDateTime lastTimeUpload; - + QDateTime lastTimeDownload = {}; /// \todo duplicate? + QDateTime lastTimeUpload = {}; }; @@ -639,7 +633,8 @@ class TorrentNodeInfo explicit TorrentNodeInfo(const QString &_host, int _port) : host(_host), port(_port) {} - QString host; + + QString host = {}; int port = 0; }; @@ -653,9 +648,9 @@ class TorrentWebSeedMetaInfo UrlSeed, HttpSeed }; - QString url; - QString auth; - QList > extraHeaders; + QString url = {}; + QString auth = {}; + QList > extraHeaders = {}; Type type = UrlSeed; }; @@ -664,12 +659,12 @@ class TorrentWebSeedMetaInfo class TorrentInitialMetaInfo { public: - QString name; - QDateTime creationDate; - QString creator; - QString comment; - QString infohash; - QString magnetLink; + QString name = {}; + QDateTime creationDate = {}; + QString creator = {}; + QString comment = {}; + QString infohash = {}; + QString magnetLink = {}; qint64 bytesMetaData = 0; @@ -678,20 +673,20 @@ class TorrentInitialMetaInfo qint64 pieceByteSize = 0; // piece's size in byte (generally 16 kB) qint64 pieceLastByteSize = 0; // last piece's size in byte, can be less than 16 kB - QString sslRootCertificate; // public certificate in x509 format + QString sslRootCertificate = {}; // public certificate in x509 format bool isPrivate = false; bool isI2P = false; - QList nodes; + QList nodes = {}; - QList files; - QList trackers; + QList files = {}; + QList trackers = {}; - QList similarTorrents; - QList collections; + QList similarTorrents = {}; + QList collections = {}; - QList webSeeds; + QList webSeeds = {}; }; /****************************************************************************** @@ -699,18 +694,18 @@ class TorrentInitialMetaInfo class TorrentMetaInfo { public: - TorrentError error; + TorrentError error = {}; - QString status; + QString status = {}; - TorrentInitialMetaInfo initialMetaInfo; + TorrentInitialMetaInfo initialMetaInfo = {}; - QList trackers2; - QList dhtNodes; + QList trackers2 = {}; + QList dhtNodes = {}; - QString outputPath; + QString outputPath = {}; - QString defaultTrackerId; + QString defaultTrackerId = {}; /// \todo flags torrent_flags_t OPTIONS torrent_flags.hpp /// \todo QString info_hash; // in case we don't have magnet link nor torrent file @@ -731,9 +726,9 @@ class TorrentMetaInfo int finishedTimeDuration = 0; int seedingTimeDuration = 0; - QDateTime addedTime; - QDateTime completedTime; - QDateTime lastSeenCompletedTime; + QDateTime addedTime = {}; + QDateTime completedTime = {}; + QDateTime lastSeenCompletedTime = {}; // -1 indicates we don't know, or we have not received any scrape data. int seedsInSwarm = -1; // number of peers in the swarm that are seeds, or have every piece in the torrent. @@ -744,15 +739,15 @@ class TorrentMetaInfo QList httpSeeds; // if not empty, this list overrides the ones given in .torrent file QList urlSeeds; /// \todo unify seeds QLists - QList defaultPeers; - QList bannedPeers; + QList defaultPeers = {}; + QList bannedPeers = {}; - QBitArray unfinishedPieces; - QBitArray downloadedPieces; - QBitArray verifiedPieces; // seed mode only + QBitArray unfinishedPieces = {}; + QBitArray downloadedPieces = {}; + QBitArray verifiedPieces = {}; // seed mode only - QDateTime lastTimeDownload; - QDateTime lastTimeUpload; + QDateTime lastTimeDownload = {}; + QDateTime lastTimeUpload = {}; }; @@ -762,20 +757,22 @@ using UniqueId = QString; struct TorrentData { - UniqueId unique_id; - TorrentMetaInfo metaInfo; - TorrentHandleInfo detail; + UniqueId unique_id = {}; + TorrentMetaInfo metaInfo = {}; + TorrentHandleInfo detail = {}; }; struct TorrentStatus { - UniqueId unique_id; - TorrentInfo info; - TorrentHandleInfo detail; + UniqueId unique_id = {}; + TorrentInfo info = {}; + TorrentHandleInfo detail = {}; }; /* Enable the type to be used with QVariant. */ Q_DECLARE_METATYPE(TorrentData) + Q_DECLARE_METATYPE(TorrentStatus) + #endif // CORE_TORRENT_MESSAGE_H diff --git a/src/core/updatechecker.cpp b/src/core/updatechecker.cpp index 612611a8..10cd319d 100644 --- a/src/core/updatechecker.cpp +++ b/src/core/updatechecker.cpp @@ -17,7 +17,7 @@ #include "updatechecker.h" #include "updatechecker_p.h" -#include +#include "../version.h" #include #include #include @@ -111,7 +111,7 @@ void UpdateChecker::onMetadataFinished() QByteArray result = reply->readAll(); QJsonDocument jsonResponse = QJsonDocument::fromJson(result); QJsonArray releases = jsonResponse.array(); - foreach (auto release, releases) { + for (auto release : releases) { QJsonObject jsonRelease = release.toObject(); @@ -131,7 +131,7 @@ void UpdateChecker::onMetadataFinished() version.body = jsonRelease["body"].toString(); auto assets = jsonRelease["assets"].toArray(); - foreach (auto asset, assets) { + for (auto asset : assets) { QJsonObject jsonAsset = asset.toObject(); auto assetName = jsonAsset["name"].toString(); @@ -163,11 +163,11 @@ void UpdateChecker::onMetadataFinished() if (!changelog.empty()) { // for no-gui check m_latestUpdateUrl = changelog.front().assetUrl; - emit updateAvailable(); + emit updateAvailableForConsole(); } storeDateTime(); - emit updateAvailable(changelog); + emit updateAvailableForGui(changelog); } /****************************************************************************** @@ -198,16 +198,15 @@ void UpdateChecker::downloadAndInstallUpdate() return; } - connect(reply, SIGNAL(downloadProgress(qint64, qint64)), - this, SLOT(onBinaryProgress(qint64, qint64))); - connect(reply, SIGNAL(finished()), - this, SLOT(onBinaryFinished())); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onBinaryProgress(qint64,qint64))); + connect(reply, SIGNAL(finished()), this, SLOT(onBinaryFinished())); } void UpdateChecker::onBinaryProgress(qint64 bytesReceived, qint64 bytesTotal) { - emit downloadProgress(static_cast(bytesReceived), - static_cast(bytesTotal)); + emit downloadProgress( + static_cast(bytesReceived), + static_cast(bytesTotal)); } void UpdateChecker::onBinaryFinished() diff --git a/src/core/updatechecker.h b/src/core/updatechecker.h index 4ce7115f..2f0df3aa 100644 --- a/src/core/updatechecker.h +++ b/src/core/updatechecker.h @@ -62,8 +62,8 @@ class UpdateChecker : public QObject QString latestUpdateUrl() const; // For Linux signals: - void updateAvailable(); // for non-GUI - void updateAvailable(UpdateChecker::ChangeLog changelog); + void updateAvailableForConsole(); // for non-GUI + void updateAvailableForGui(UpdateChecker::ChangeLog changelog); void downloadProgress(qsizetype bytesReceived, qsizetype bytesTotal); void updateDownloadFinished(); void updateError(QString errorMessage); diff --git a/src/core/updatechecker_p.h b/src/core/updatechecker_p.h index f91c1eef..ab59bb22 100644 --- a/src/core/updatechecker_p.h +++ b/src/core/updatechecker_p.h @@ -25,9 +25,10 @@ namespace UpdateCheckerNS QString cleanTag(const QString &tag) { + static QRegularExpression re("[^\\d\\s]"); auto cleaned = tag; cleaned = cleaned.replace(u'.', u' '); - cleaned.remove(QRegularExpression("[^\\d\\s]")); + cleaned.remove(re); cleaned = cleaned.simplified(); cleaned = cleaned.replace(u' ', u'.'); return cleaned; diff --git a/src/dialogs/addbatchdialog.cpp b/src/dialogs/addbatchdialog.cpp index a0561257..c258ac7f 100644 --- a/src/dialogs/addbatchdialog.cpp +++ b/src/dialogs/addbatchdialog.cpp @@ -17,7 +17,7 @@ #include "addbatchdialog.h" #include "ui_addbatchdialog.h" -#include +#include #include #include #include @@ -39,8 +39,10 @@ #include -AddBatchDialog::AddBatchDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent) +AddBatchDialog::AddBatchDialog( + const QUrl &url, + DownloadManager *downloadManager, + Settings *settings, QWidget *parent) : QDialog(parent) , ui(new Ui::AddBatchDialog) , m_downloadManager(downloadManager) @@ -48,7 +50,9 @@ AddBatchDialog::AddBatchDialog(const QUrl &url, DownloadManager *downloadManager { ui->setupUi(this); - setWindowTitle(QString("%0 - %1").arg(STR_APPLICATION_NAME, tr("Add Batch and Single File"))); + using namespace Qt::Literals::StringLiterals; + + setWindowTitle(STR_APPLICATION_NAME % " - " % tr("Add Batch and Single File")); Theme::setIcons(this, { {ui->logo, "add-batch"} }); @@ -63,19 +67,23 @@ AddBatchDialog::AddBatchDialog(const QUrl &url, DownloadManager *downloadManager ui->urlLineEdit->setClearButtonEnabled(true); ui->titleListLabel->setToolTip( - QString("

        " - "%0" - "

        - " - "%1" - "

        - " - "%2" - "

        - " - "%3" - "

        ").arg( - tr("Batch descriptors:"), - tr("Must start with '[' or '('"), - tr("Must contain two numbers, separated by ':', '-' or a space character"), - tr("Must end with ']' or ')'"))); + QString( + "

        " + "%0" + "

        - " + "%1" + "

        - " + "%2" + "

        - " + "%3" + "

        " + ).arg( + tr("Batch descriptors:"), + tr("Must start with '[' or '('"), + tr("Must contain two numbers, separated by ':', '-' or a space character"), + tr("Must end with ']' or ')'") + ) + ); if (m_settings && m_settings->isCustomBatchEnabled()) { ui->tagButton_Custom->setText(m_settings->customBatchButtonLabel()); @@ -84,8 +92,7 @@ AddBatchDialog::AddBatchDialog(const QUrl &url, DownloadManager *downloadManager ui->tagButton_Custom->setVisible(false); } - connect(ui->urlLineEdit, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenu(const QPoint &))); + connect(ui->urlLineEdit, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(ui->tagButton_1_10, SIGNAL(released()), this, SLOT(insert_1_to_10())); connect(ui->tagButton_1_100, SIGNAL(released()), this, SLOT(insert_1_to_100())); @@ -128,7 +135,7 @@ void AddBatchDialog::writeUiSettings() */ void AddBatchDialog::quickDownload(const QUrl &url, DownloadManager *downloadManager) { - if (downloadManager == Q_NULLPTR) { + if (downloadManager == nullptr) { return; } // Remove trailing / and \ and . @@ -333,7 +340,7 @@ QList AddBatchDialog::createItems(const QUrl &inputUrl) const { QList items; const QStringList urls = Regex::interpret(inputUrl); - foreach (auto url, urls) { + for (auto url : urls) { items << createItem(url); } return items; diff --git a/src/dialogs/addbatchdialog.h b/src/dialogs/addbatchdialog.h index b2ca30e4..9f9f4499 100644 --- a/src/dialogs/addbatchdialog.h +++ b/src/dialogs/addbatchdialog.h @@ -33,16 +33,15 @@ class AddBatchDialog : public QDialog Q_OBJECT public: - explicit AddBatchDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent = Q_NULLPTR); - ~AddBatchDialog() Q_DECL_OVERRIDE; + explicit AddBatchDialog(const QUrl &url, DownloadManager *downloadManager, Settings *settings, QWidget *parent = nullptr); + ~AddBatchDialog() override; static void quickDownload(const QUrl &url, DownloadManager *downloadManager); public slots: - void accept() Q_DECL_OVERRIDE; + void accept() override; virtual void acceptPaused(); - void reject() Q_DECL_OVERRIDE; + void reject() override; private slots: void showContextMenu(const QPoint &pos); diff --git a/src/dialogs/addcontentdialog.cpp b/src/dialogs/addcontentdialog.cpp index d2dd68d2..7d7a75df 100644 --- a/src/dialogs/addcontentdialog.cpp +++ b/src/dialogs/addcontentdialog.cpp @@ -17,7 +17,7 @@ #include "addcontentdialog.h" #include "ui_addcontentdialog.h" -#include +#include #include #include #include @@ -52,12 +52,13 @@ constexpr int column_download_width = 400; constexpr int column_mask_width = 200; -static QList createItems(const QList &resources, - DownloadManager *downloadManager, - const Settings *settings) +static QList createItems( + const QList &resources, + DownloadManager *downloadManager, + const Settings *settings) { QList items; - foreach (auto resource, resources) { + for (auto resource : resources) { if (settings && settings->isHttpReferringPageEnabled()) { resource->setReferringPage(settings->httpReferringPage()); } @@ -69,14 +70,13 @@ static QList createItems(const QList &resources, } -AddContentDialog::AddContentDialog(DownloadManager *downloadManager, - Settings *settings, QWidget *parent) +AddContentDialog::AddContentDialog(DownloadManager *downloadManager, Settings *settings, QWidget *parent) : QDialog(parent) , ui(new Ui::AddContentDialog) , m_downloadManager(downloadManager) , m_model(new Model(this)) #ifdef USE_QT_WEBENGINE - , m_webEngineView(Q_NULLPTR) + , m_webEngineView(nullptr) #endif , m_settings(settings) { @@ -197,23 +197,17 @@ void AddContentDialog::loadUrl(const QUrl &url) /* Only load source, not media */ QWebEngineSettings *settings = m_webEngineView->settings()->globalSettings(); settings->setAttribute(QWebEngineSettings::AutoLoadImages, false); -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) settings->setAttribute(QWebEngineSettings::AutoLoadIconsForPage, false); m_webEngineView->page()->setAudioMuted(true); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) settings->setAttribute(QWebEngineSettings::ShowScrollBars, false); -#endif -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) settings->setAttribute(QWebEngineSettings::PdfViewerEnabled, false); -#endif } m_webEngineView->load(m_url); #else qInfo("Loading URL. HTML parser is Google Gumbo."); NetworkManager *networkManager = m_downloadManager->networkManager(); QNetworkReply *reply = networkManager->get(m_url); - connect(reply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(onDownloadProgress(qint64, qint64))); + connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(onDownloadProgress(qint64,qint64))); connect(reply, SIGNAL(finished()), this, SLOT(onFinished())); #endif setProgressInfo(0, tr("Connecting...")); @@ -260,7 +254,7 @@ void AddContentDialog::onDownloadProgress(qint64 bytesReceived, qint64 bytesTota /* Between 1% and 90% */ int percent = 1; if (bytesTotal > 0) { - percent = qMin(qCeil(qreal(90 * bytesReceived) / bytesTotal), 90); + percent = qMin(qCeil(90 * static_cast(bytesReceived) / static_cast(bytesTotal)), 90); } setProgressInfo(percent, tr("Downloading...")); } @@ -270,7 +264,7 @@ void AddContentDialog::onFinished() auto reply = qobject_cast(sender()); if (reply) { if (reply->error() == QNetworkReply::NoError) { - QByteArray downloadedData = reply->readAll(); + auto downloadedData = reply->readAll(); reply->deleteLater(); parseHtml(downloadedData); } else { @@ -386,26 +380,27 @@ void AddContentDialog::setProgressInfo(int percent, const QString &text) ******************************************************************************/ void AddContentDialog::onSelectionChanged() { - const ResourceModel *currentModel = m_model->currentModel(); - const int selectionCount = currentModel->selection().count(); + auto currentModel = m_model->currentModel(); + auto selectionCount = currentModel->selection().count(); if (selectionCount == 0) { ui->tipLabel->setText(tr("After selecting links, click on Start!")); } else { - const int count = currentModel->items().count(); + auto count = currentModel->items().count(); ui->tipLabel->setText(tr("Selected links: %0 of %1").arg( QString::number(selectionCount), QString::number(count))); } - onChanged(QString()); + onChanged({}); } /****************************************************************************** ******************************************************************************/ -void AddContentDialog::onChanged(QString) +void AddContentDialog::onChanged(const QString &value) { - const ResourceModel *currentModel = m_model->currentModel(); - const int selectionCount = currentModel->selection().count(); - const bool enabled = + Q_UNUSED(value) + auto currentModel = m_model->currentModel(); + auto selectionCount = currentModel->selection().count(); + auto enabled = !ui->pathWidget->currentPath().isEmpty() && !ui->maskWidget->currentMask().isEmpty() && selectionCount > 0; @@ -419,7 +414,7 @@ void AddContentDialog::refreshFilters() { QList filters = m_settings->filters(); ui->filterWidget->clearFilters(); - foreach (auto filter, filters) { + for (auto filter : filters) { ui->filterWidget->addFilter(filter.name(), filter.regex()); } } diff --git a/src/dialogs/addcontentdialog.h b/src/dialogs/addcontentdialog.h index 734e03e0..b8c9ef60 100644 --- a/src/dialogs/addcontentdialog.h +++ b/src/dialogs/addcontentdialog.h @@ -40,15 +40,14 @@ class AddContentDialog : public QDialog enum Bypass { None, Start, StartPaused }; // Dirty hack to NOT show the dialog public: - explicit AddContentDialog(DownloadManager *downloadManager, - Settings *settings, QWidget *parent); - ~AddContentDialog() Q_DECL_OVERRIDE; + explicit AddContentDialog(DownloadManager *downloadManager, Settings *settings, QWidget *parent); + ~AddContentDialog() override; bool loadResources(const QString &message); void loadUrl(const QUrl &url); protected: - void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *event) override; signals: #ifdef USE_QT_WEBENGINE @@ -56,10 +55,10 @@ class AddContentDialog : public QDialog #endif public slots: - int exec() Q_DECL_OVERRIDE; - void accept() Q_DECL_OVERRIDE; + int exec() override; + void accept() override; virtual void acceptPaused(); - void reject() Q_DECL_OVERRIDE; + void reject() override; private slots: #ifdef USE_QT_WEBENGINE @@ -71,7 +70,7 @@ private slots: void onFinished(); #endif void onSelectionChanged(); - void onChanged(QString); + void onChanged(const QString &value); void refreshFilters(); private: diff --git a/src/dialogs/addstreamdialog.cpp b/src/dialogs/addstreamdialog.cpp index f80c03f7..25cb7e05 100644 --- a/src/dialogs/addstreamdialog.cpp +++ b/src/dialogs/addstreamdialog.cpp @@ -17,7 +17,7 @@ #include "addstreamdialog.h" #include "ui_addstreamdialog.h" -#include +#include #include #include #include @@ -30,8 +30,10 @@ #include -AddStreamDialog::AddStreamDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent) +AddStreamDialog::AddStreamDialog( + const QUrl &url, + DownloadManager *downloadManager, + Settings *settings, QWidget *parent) : QDialog(parent) , ui(new Ui::AddStreamDialog) , m_downloadManager(downloadManager) @@ -152,7 +154,7 @@ void AddStreamDialog::onCollected(const QList &streamObjects) { setGuiEnabled(true); QList copy; - foreach (auto streamObject, streamObjects) { + for (auto streamObject : streamObjects) { auto config = streamObject.config(); config.overview.markWatched = m_settings->isStreamMarkWatchedEnabled(); config.subtitle.writeSubtitle = m_settings->isStreamSubtitleEnabled(); @@ -195,7 +197,7 @@ void AddStreamDialog::doAccept(bool started) QList AddStreamDialog::createItems() const { QList items; - foreach (auto item, ui->streamListWidget->selection()) { + for (auto item : ui->streamListWidget->selection()) { items << createItem(item); } return items; diff --git a/src/dialogs/addstreamdialog.h b/src/dialogs/addstreamdialog.h index 9ceaa284..78b8334c 100644 --- a/src/dialogs/addstreamdialog.h +++ b/src/dialogs/addstreamdialog.h @@ -34,16 +34,15 @@ class AddStreamDialog : public QDialog { Q_OBJECT public: - explicit AddStreamDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent = Q_NULLPTR); - ~AddStreamDialog() Q_DECL_OVERRIDE; + explicit AddStreamDialog(const QUrl &url, DownloadManager *downloadManager, Settings *settings, QWidget *parent = nullptr); + ~AddStreamDialog() override; static bool isStreamUrl(const QUrl &url, const Settings *settings); public slots: - void accept() Q_DECL_OVERRIDE; + void accept() override; virtual void acceptPaused(); - void reject() Q_DECL_OVERRIDE; + void reject() override; private slots: void onContinueClicked(); diff --git a/src/dialogs/addtorrentdialog.cpp b/src/dialogs/addtorrentdialog.cpp index fa3b8445..05bd0ab5 100644 --- a/src/dialogs/addtorrentdialog.cpp +++ b/src/dialogs/addtorrentdialog.cpp @@ -17,7 +17,7 @@ #include "addtorrentdialog.h" #include "ui_addtorrentdialog.h" -#include +#include #include #include #include @@ -35,8 +35,10 @@ #include -AddTorrentDialog::AddTorrentDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent) +AddTorrentDialog::AddTorrentDialog( + const QUrl &url, + DownloadManager *downloadManager, + Settings *settings, QWidget *parent) : QDialog(parent) , ui(new Ui::AddTorrentDialog) , m_downloadManager(downloadManager) diff --git a/src/dialogs/addtorrentdialog.h b/src/dialogs/addtorrentdialog.h index f111afbf..30161c91 100644 --- a/src/dialogs/addtorrentdialog.h +++ b/src/dialogs/addtorrentdialog.h @@ -32,16 +32,15 @@ class AddTorrentDialog : public QDialog { Q_OBJECT public: - explicit AddTorrentDialog(const QUrl &url, DownloadManager *downloadManager, - Settings *settings, QWidget *parent = Q_NULLPTR); - ~AddTorrentDialog() Q_DECL_OVERRIDE; + explicit AddTorrentDialog(const QUrl &url, DownloadManager *downloadManager, Settings *settings, QWidget *parent = nullptr); + ~AddTorrentDialog() override; static bool isTorrentUrl(const QUrl &url); public slots: - void accept() Q_DECL_OVERRIDE; + void accept() override; virtual void acceptPaused(); - void reject() Q_DECL_OVERRIDE; + void reject() override; private slots: void onChanged(QString); diff --git a/src/dialogs/addurlsdialog.cpp b/src/dialogs/addurlsdialog.cpp index 5643b4dc..ca880da3 100644 --- a/src/dialogs/addurlsdialog.cpp +++ b/src/dialogs/addurlsdialog.cpp @@ -17,7 +17,7 @@ #include "addurlsdialog.h" #include "ui_addurlsdialog.h" -#include +#include #include #include #include @@ -33,8 +33,10 @@ #include -AddUrlsDialog::AddUrlsDialog(const QString &text, DownloadManager *downloadManager, - Settings *settings, QWidget *parent) +AddUrlsDialog::AddUrlsDialog( + const QString &text, + DownloadManager *downloadManager, + Settings *settings, QWidget *parent) : QDialog(parent) , ui(new Ui::AddUrlsDialog) , m_fakeUrlLineEdit(new QLineEdit(this)) diff --git a/src/dialogs/addurlsdialog.h b/src/dialogs/addurlsdialog.h index 0bf565a8..b8559d3e 100644 --- a/src/dialogs/addurlsdialog.h +++ b/src/dialogs/addurlsdialog.h @@ -33,14 +33,13 @@ class AddUrlsDialog : public QDialog { Q_OBJECT public: - explicit AddUrlsDialog(const QString &text, DownloadManager *downloadManager, - Settings *settings, QWidget *parent = Q_NULLPTR); - ~AddUrlsDialog() Q_DECL_OVERRIDE; + explicit AddUrlsDialog(const QString &text, DownloadManager *downloadManager, Settings *settings, QWidget *parent = nullptr); + ~AddUrlsDialog() override; public slots: - void accept() Q_DECL_OVERRIDE; + void accept() override; virtual void acceptPaused(); - void reject() Q_DECL_OVERRIDE; + void reject() override; private slots: void onChanged(QString); diff --git a/src/dialogs/batchrenamedialog.cpp b/src/dialogs/batchrenamedialog.cpp index 32996efc..3437f647 100644 --- a/src/dialogs/batchrenamedialog.cpp +++ b/src/dialogs/batchrenamedialog.cpp @@ -17,7 +17,7 @@ #include "batchrenamedialog.h" #include "ui_batchrenamedialog.h" -#include +#include #include #include #include @@ -95,7 +95,7 @@ void BatchRenameDialog::accept() ******************************************************************************/ void BatchRenameDialog::renameToDefault() { - foreach (auto item, m_items) { + for (auto item : m_items) { auto downloadItem = dynamic_cast(item); rename(downloadItem, QString()); } @@ -117,7 +117,7 @@ void BatchRenameDialog::renameToEnumeration() } auto i = from; - foreach (auto item, m_items) { + for (auto item : m_items) { auto downloadItem = dynamic_cast(item); auto newName = QString("%0").arg(QString::number(i), digits, QLatin1Char('0')); rename(downloadItem, newName); diff --git a/src/dialogs/batchrenamedialog.h b/src/dialogs/batchrenamedialog.h index 74866708..5b1dea53 100644 --- a/src/dialogs/batchrenamedialog.h +++ b/src/dialogs/batchrenamedialog.h @@ -33,11 +33,11 @@ class BatchRenameDialog : public QDialog Q_OBJECT public: explicit BatchRenameDialog(const QList &items, QWidget *parent); - ~BatchRenameDialog() Q_DECL_OVERRIDE; + ~BatchRenameDialog() override; public slots: - void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; - void accept() Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *) override; + void accept() override; private slots: void onComboboxChanged(int index); @@ -63,7 +63,7 @@ class PopupItemDelegate: public QStyledItemDelegate public: using QStyledItemDelegate::QStyledItemDelegate; - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; #endif // DIALOGS_BATCH_RENAME_DIALOG_H diff --git a/src/dialogs/compilerdialog.cpp b/src/dialogs/compilerdialog.cpp index 939b272a..3828bbc4 100644 --- a/src/dialogs/compilerdialog.cpp +++ b/src/dialogs/compilerdialog.cpp @@ -17,7 +17,8 @@ #include "compilerdialog.h" #include "ui_compilerdialog.h" -#include +#include "../version_3rd.h" +#include #include #include @@ -146,8 +147,8 @@ void CompilerDialog::populateOpenSSL() libCrypto = QLatin1String("libeay32"); #elif defined(Q_OS_WIN32) && defined(Q_OS_WIN64) // 32-bit or 64-bit - libSsl = QLatin1String("libssl-1_1-x64"); - libCrypto = QLatin1String("libcrypto-1_1-x64"); + libSsl = QLatin1String("libssl-3-x64"); + libCrypto = QLatin1String("libcrypto-3-x64"); #elif defined(Q_OS_UNIX) libSsl = QLatin1String("libssl"); @@ -190,7 +191,7 @@ QString CompilerDialog::getVersionString(const QString &fName) } // VerQueryValue - VS_FIXEDFILEINFO *lpBuffer = Q_NULLPTR; + VS_FIXEDFILEINFO *lpBuffer = nullptr; dwLen = sizeof( VS_FIXEDFILEINFO ); // UINT uLen; if (VerQueryValue( diff --git a/src/dialogs/compilerdialog.h b/src/dialogs/compilerdialog.h index e603be00..5ccc1944 100644 --- a/src/dialogs/compilerdialog.h +++ b/src/dialogs/compilerdialog.h @@ -15,8 +15,8 @@ class CompilerDialog : public QDialog Q_OBJECT public: - explicit CompilerDialog(QWidget *parent = Q_NULLPTR); - ~CompilerDialog() Q_DECL_OVERRIDE; + explicit CompilerDialog(QWidget *parent = nullptr); + ~CompilerDialog() override; private slots: void onOkButtonReleased(); diff --git a/src/dialogs/editiondialog.cpp b/src/dialogs/editiondialog.cpp index 2913cc6a..9e9bc89d 100644 --- a/src/dialogs/editiondialog.cpp +++ b/src/dialogs/editiondialog.cpp @@ -17,7 +17,7 @@ #include "editiondialog.h" #include "ui_editiondialog.h" -#include +#include #include #include #include @@ -51,7 +51,7 @@ EditionDialog::EditionDialog(const QList &items, QWidget *parent ui->warningLabel->setVisible(false); ui->editor->clear(); - foreach (auto item, items) { + for (auto item : items) { auto downloadItem = dynamic_cast(item); if (downloadItem) { auto resource = downloadItem->resource(); @@ -79,8 +79,8 @@ void EditionDialog::accept() { writeSettings(); if (ui->editor->isModified()) { - const int itemCount = m_items.count(); - const int lineCount = ui->editor->count(); + auto itemCount = m_items.count(); + auto lineCount = ui->editor->count(); if (itemCount != lineCount) { return; // Cancel action } @@ -108,10 +108,10 @@ void EditionDialog::onTextChanged() ******************************************************************************/ void EditionDialog::applyChanges() { - const int itemCount = m_items.count(); - const int lineCount = ui->editor->count(); + auto itemCount = m_items.count(); + auto lineCount = ui->editor->count(); Q_ASSERT(itemCount == lineCount); - for (int index = 0; index < itemCount; ++index) { + for (auto index = 0; index < itemCount; ++index) { auto item = m_items.at(index); auto downloadItem = dynamic_cast(item); diff --git a/src/dialogs/editiondialog.h b/src/dialogs/editiondialog.h index fe2f4dc4..61516841 100644 --- a/src/dialogs/editiondialog.h +++ b/src/dialogs/editiondialog.h @@ -32,11 +32,11 @@ class EditionDialog : public QDialog Q_OBJECT public: explicit EditionDialog(const QList &items, QWidget *parent); - ~EditionDialog() Q_DECL_OVERRIDE; + ~EditionDialog() override; public slots: - void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; - void accept() Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *) override; + void accept() override; private slots: void onTextChanged(); diff --git a/src/dialogs/homedialog.cpp b/src/dialogs/homedialog.cpp index ce1c5edc..433404ec 100644 --- a/src/dialogs/homedialog.cpp +++ b/src/dialogs/homedialog.cpp @@ -17,7 +17,7 @@ #include "homedialog.h" #include "ui_homedialog.h" -#include +#include #include #include @@ -76,12 +76,12 @@ void HomeDialog::acceptUrls() void HomeDialog::propagateIcons() { - const QMap map = { + const QHash hash = { {ui->buttonContent, "add-content"}, {ui->buttonBatch , "add-batch"}, {ui->buttonStream , "add-stream"}, {ui->buttonTorrent, "add-torrent"}, {ui->buttonUrls , "add-urls"} }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } diff --git a/src/dialogs/homedialog.h b/src/dialogs/homedialog.h index 0bda59d5..92566818 100644 --- a/src/dialogs/homedialog.h +++ b/src/dialogs/homedialog.h @@ -34,8 +34,8 @@ class HomeDialog : public QDialog Torrent, Urls }; - explicit HomeDialog(QWidget *parent = Q_NULLPTR); - ~HomeDialog() Q_DECL_OVERRIDE; + explicit HomeDialog(QWidget *parent = nullptr); + ~HomeDialog() override; private slots: void acceptContent(); diff --git a/src/dialogs/informationdialog.cpp b/src/dialogs/informationdialog.cpp index a421af70..34def23d 100644 --- a/src/dialogs/informationdialog.cpp +++ b/src/dialogs/informationdialog.cpp @@ -17,7 +17,7 @@ #include "informationdialog.h" #include "ui_informationdialog.h" -#include +#include #include #include #include diff --git a/src/dialogs/informationdialog.h b/src/dialogs/informationdialog.h index 4684e6f3..1c4914d3 100644 --- a/src/dialogs/informationdialog.h +++ b/src/dialogs/informationdialog.h @@ -31,10 +31,10 @@ class InformationDialog : public QDialog Q_OBJECT public: explicit InformationDialog(const QList &jobs, QWidget *parent); - ~InformationDialog() Q_DECL_OVERRIDE; + ~InformationDialog() override; public slots: - void accept() Q_DECL_OVERRIDE; + void accept() override; private slots: void wrapLog(bool enabled); diff --git a/src/dialogs/preferencedialog.cpp b/src/dialogs/preferencedialog.cpp index 2c85ee0a..0f5c6faf 100644 --- a/src/dialogs/preferencedialog.cpp +++ b/src/dialogs/preferencedialog.cpp @@ -17,7 +17,7 @@ #include "preferencedialog.h" #include "ui_preferencedialog.h" -#include +#include #include #include #include @@ -133,9 +133,9 @@ void PreferenceDialog::connectUi() connect(ui->httpReferringPageCheckBox, SIGNAL(toggled(bool)), ui->httpReferringPageLineEdit, SLOT(setEnabled(bool))); // Tab Filters - connect(ui->filterTableWidget, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(filterContextMenu(const QPoint &))); + connect(ui->filterTableWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(filterContextMenu(QPoint))); connect(ui->filterTableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(filterSelectionChanged())); - connect(ui->filterTableWidget, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(filterChanged(QTableWidgetItem *))); + connect(ui->filterTableWidget, SIGNAL(itemChanged(QTableWidgetItem*)), this, SLOT(filterChanged(QTableWidgetItem*))); connect(ui->filterAddButton, SIGNAL(released()), this, SLOT(filterAdded())); connect(ui->filterUpdateButton, SIGNAL(released()), this, SLOT(filterUpdated())); @@ -279,13 +279,13 @@ void PreferenceDialog::restylizeUi() ui->tabWidget->setTabIcon(6, QIcon::fromTheme("preference-advanced")); // Restylize icons - const QMap map = { - {ui->streamHelp, "help"}, - {ui->concurrentFragmentHelp, "help"}, - {ui->httpUserAgentHelp, "help"}, - {ui->httpReferringPageHelp, "help"} + const QHash hash = { + {ui->streamHelp, "help"}, + {ui->concurrentFragmentHelp, "help"}, + {ui->httpUserAgentHelp, "help"}, + {ui->httpReferringPageHelp, "help"} }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } /****************************************************************************** @@ -305,7 +305,7 @@ void PreferenceDialog::filterSelectionChanged() ui->filterRegexLineEdit->clear(); ui->filterUpdateButton->setEnabled(false); QList items = ui->filterTableWidget->selectedItems(); - foreach (auto item, items) { + for (auto item : items) { if (item->column() == 1) { ui->filterCaptionLineEdit->setText(item->text()); ui->filterUpdateButton->setEnabled(!item->text().isEmpty()); @@ -355,7 +355,7 @@ void PreferenceDialog::filterUpdated() items << ui->filterTableWidget->item(row, col); } } - foreach (auto item, items) { + for (auto item : items) { if (item->column() == 0) { item->setText(QLatin1String("")); } else if (item->column() == 1) { @@ -643,7 +643,7 @@ void PreferenceDialog::write() void PreferenceDialog::setStreamHosts(const QStringList &streamHosts) { ui->streamHostPlainTextEdit->clear(); - foreach (auto streamHost, streamHosts) { + for (auto streamHost : streamHosts) { ui->streamHostPlainTextEdit->appendPlainText(streamHost); } @@ -698,7 +698,7 @@ void PreferenceDialog::setupStreamToolTip() QString tooltip; tooltip += ""; tooltip += QString("

        %0

        ").arg(tr("Examples:")); - foreach (auto preset, presets) { + for (auto preset : presets) { tooltip += "

        " "- " @@ -795,7 +795,7 @@ void PreferenceDialog::setFilters(const QList &filters) while (ui->filterTableWidget->rowCount() > 0) { ui->filterTableWidget->removeRow(0); } - foreach (auto filter, filters) { + for (auto filter : filters) { addFilter(filter); } } diff --git a/src/dialogs/preferencedialog.h b/src/dialogs/preferencedialog.h index 9e591c7b..9d23a65a 100644 --- a/src/dialogs/preferencedialog.h +++ b/src/dialogs/preferencedialog.h @@ -33,18 +33,18 @@ class PreferenceDialog : public QDialog public: explicit PreferenceDialog(Settings *settings, QWidget *parent); - ~PreferenceDialog() Q_DECL_OVERRIDE; + ~PreferenceDialog() override; signals: void checkUpdate(); protected: - void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *event) override; + void changeEvent(QEvent *event) override; public slots: - void accept() Q_DECL_OVERRIDE; - void reject() Q_DECL_OVERRIDE; + void accept() override; + void reject() override; virtual void restoreDefaultSettings(); private slots: diff --git a/src/dialogs/streamdialog.cpp b/src/dialogs/streamdialog.cpp index baada4bd..2fbccadc 100644 --- a/src/dialogs/streamdialog.cpp +++ b/src/dialogs/streamdialog.cpp @@ -17,7 +17,7 @@ #include "streamdialog.h" #include "ui_streamdialog.h" -#include +#include #include #include @@ -101,12 +101,12 @@ void StreamDialog::onCollected(const QStringList &extractors, const QStringList ui->plainTextEdit->appendPlainText(QString()); ui->plainTextEdit->appendPlainText(QString("%0\t%1").arg(tr("Site"), tr("Description"))); ui->plainTextEdit->appendPlainText(QString()); - for (int i = 0; i < count; ++i) { + for (auto i = 0; i < count; ++i) { ui->plainTextEdit->appendPlainText(QString("%0\t%1").arg( extractors.at(i), descriptions.at(i))); } - for (int i = count, total = extractors.count(); i < total; ++i) { + for (auto i = count, total = extractors.count(); i < total; ++i) { ui->plainTextEdit->appendPlainText(QString("%0").arg( extractors.at(i))); } diff --git a/src/dialogs/streamdialog.h b/src/dialogs/streamdialog.h index 4a5072b8..b88d2aad 100644 --- a/src/dialogs/streamdialog.h +++ b/src/dialogs/streamdialog.h @@ -28,8 +28,8 @@ class StreamDialog : public QDialog Q_OBJECT public: - explicit StreamDialog(QWidget *parent = Q_NULLPTR); - ~StreamDialog() Q_DECL_OVERRIDE; + explicit StreamDialog(QWidget *parent = nullptr); + ~StreamDialog() override; private slots: void onOkButtonReleased(); diff --git a/src/dialogs/tutorialdialog.cpp b/src/dialogs/tutorialdialog.cpp index a665390f..a89edfeb 100644 --- a/src/dialogs/tutorialdialog.cpp +++ b/src/dialogs/tutorialdialog.cpp @@ -17,7 +17,7 @@ #include "tutorialdialog.h" #include "ui_tutorialdialog.h" -#include +#include #include #include diff --git a/src/dialogs/tutorialdialog.h b/src/dialogs/tutorialdialog.h index f2018d87..a9877566 100644 --- a/src/dialogs/tutorialdialog.h +++ b/src/dialogs/tutorialdialog.h @@ -30,11 +30,11 @@ class TutorialDialog : public QDialog Q_OBJECT public: - explicit TutorialDialog(Settings *settings, QWidget *parent = Q_NULLPTR); - ~TutorialDialog() Q_DECL_OVERRIDE; + explicit TutorialDialog(Settings *settings, QWidget *parent = nullptr); + ~TutorialDialog() override; public slots: - void closeEvent(QCloseEvent *) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *) override; private: Ui::TutorialDialog *ui; diff --git a/src/dialogs/updatedialog.cpp b/src/dialogs/updatedialog.cpp index f8d4899a..4fb33c0a 100644 --- a/src/dialogs/updatedialog.cpp +++ b/src/dialogs/updatedialog.cpp @@ -17,7 +17,7 @@ #include "updatedialog.h" #include "ui_updatedialog.h" -#include +#include #include #include @@ -47,14 +47,10 @@ UpdateDialog::UpdateDialog(UpdateChecker *updateChecker, QWidget *parent) connect(ui->checkButton, SIGNAL(released()), this, SLOT(check())); connect(ui->installButton, SIGNAL(released()), this, SLOT(install())); - connect(m_updateChecker, SIGNAL(updateAvailable(UpdateChecker::ChangeLog)), - this, SLOT(onUpdateAvailable(UpdateChecker::ChangeLog))); - connect(m_updateChecker, SIGNAL(downloadProgress(qsizetype, qsizetype)), - this, SLOT(onDownloadProgress(qsizetype, qsizetype))); - connect(m_updateChecker, SIGNAL(updateDownloadFinished()), - this, SLOT(onUpdateDownloadFinished())); - connect(m_updateChecker, SIGNAL(updateError(QString)), - this, SLOT(onUpdateError(QString))); + connect(m_updateChecker, SIGNAL(updateAvailableForGui(UpdateChecker::ChangeLog)), this, SLOT(updateAvailableForGui(UpdateChecker::ChangeLog))); + connect(m_updateChecker, SIGNAL(downloadProgress(qsizetype,qsizetype)), this, SLOT(onDownloadProgress(qsizetype,qsizetype))); + connect(m_updateChecker, SIGNAL(updateDownloadFinished()), this, SLOT(onUpdateDownloadFinished())); + connect(m_updateChecker, SIGNAL(updateError(QString)), this, SLOT(onUpdateError(QString))); ui->stackedWidget->setCurrentWidget(ui->pageAlreadyUpToDate); ui->progressBar->setVisible(false); @@ -124,7 +120,7 @@ void UpdateDialog::install() /****************************************************************************** ******************************************************************************/ -void UpdateDialog::onUpdateAvailable(const UpdateChecker::ChangeLog &changelog) +void UpdateDialog::onUpdateAvailableForGui(const UpdateChecker::ChangeLog &changelog) { if (!changelog.empty()) { ui->stackedWidget->setCurrentWidget(ui->pageNewVersionAvailable); @@ -172,7 +168,7 @@ void UpdateDialog::onDownloadProgress(qsizetype bytesReceived, qsizetype bytesTo int percent = 0; if (bytesTotal != 0) { if (bytesReceived < bytesTotal) { - percent = qFloor(qreal(100 * bytesReceived) / bytesTotal); + percent = qFloor(100 * static_cast(bytesReceived) / static_cast(bytesTotal)); } else { percent = 100; } diff --git a/src/dialogs/updatedialog.h b/src/dialogs/updatedialog.h index d1a98eb3..dddb31f2 100644 --- a/src/dialogs/updatedialog.h +++ b/src/dialogs/updatedialog.h @@ -20,14 +20,14 @@ class UpdateDialog : public QDialog Q_OBJECT public: - explicit UpdateDialog(UpdateChecker *updateChecker, QWidget *parent = Q_NULLPTR); - ~UpdateDialog() Q_DECL_OVERRIDE; + explicit UpdateDialog(UpdateChecker *updateChecker, QWidget *parent = nullptr); + ~UpdateDialog() override; private slots: void check(); void install(); - void onUpdateAvailable(const UpdateChecker::ChangeLog &changelog); + void onUpdateAvailableForGui(const UpdateChecker::ChangeLog &changelog); void onDownloadProgress(qsizetype bytesReceived, qsizetype bytesTotal); void onUpdateDownloadFinished(); void onUpdateError(const QString &errorMessage); diff --git a/src/globals.h b/src/globals.h deleted file mode 100644 index 0093242b..00000000 --- a/src/globals.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - DownZemAll! - Copyright (C) 2019-present Sebastien Vavassori - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; If not, see . - */ - -#ifndef GLOBALS_H -#define GLOBALS_H - -#include "builddefs.h" -#include "version.h" -#include - -const QString STR_APPLICATION_NAME("DownZemAll!"); -const QLatin1String STR_APPLICATION_VERSION(APP_VERSION); -const QLatin1String STR_APPLICATION_DATE("2020"); -const QString STR_APPLICATION_AUTHOR("Sébastien Vavassori"); -const QString STR_APPLICATION_WEBSITE("https://github.com/setvisible/DownZemAll"); -const QString STR_TUTORIAL_WEBSITE("https://setvisible.github.io/DownZemAll/category/tutorial.html"); - -const QString STR_GITHUB_OWNER("setvisible"); -const QString STR_GITHUB_REPO("DownZemAll"); -const QString STR_GITHUB_REPO_ADDRESS = QString("https://github.com/%0/%1").arg(STR_GITHUB_OWNER, STR_GITHUB_REPO); -const QString STR_GITHUB_RELEASES_API = QString("https://api.github.com/repos/%0/%1/releases").arg(STR_GITHUB_OWNER, STR_GITHUB_REPO); - -/* - * Remark: the "Application Organization Name" - * is the string that appears in the Windows registry. - * It should contain only ASCII characters for maximizing - * compatibility with Windows 7/8/10 and following. - */ -const QString STR_APPLICATION_ORGANIZATION("Sebastien Vavassori"); - - -/* Something like "2017-05-20_15:36:58" */ -const QString STR_APPLICATION_BUILD = - QString("%1-%2-%3_%4:%5:%6") - .arg(BUILD_YEAR, 4, 10, QChar('0')) - .arg(BUILD_MONTH, 2, 10, QChar('0')) - .arg(BUILD_DAY, 2, 10, QChar('0')) - .arg(BUILD_HOUR, 2, 10, QChar('0')) - .arg(BUILD_MIN, 2, 10, QChar('0')) - .arg(BUILD_SEC, 2, 10, QChar('0')); - - -/* Compiler Info */ -const QString STR_COMPILER_WORDSIZE(QString("%0-bit").arg(QSysInfo::WordSize)); -const QString STR_COMPILER_BUILD_ABI = QSysInfo::buildAbi(); -const QString STR_COMPILER_BUILD_CPU = QSysInfo::buildCpuArchitecture(); - -const QString STR_COMPILER_NAME= -#if defined(Q_CC_BOR) - "Borland/Turbo C++" -#elif defined(Q_CC_CDS) - "Reliant C++" -#elif defined(Q_CC_COMEAU) - "Comeau C++" -#elif defined(Q_CC_DEC) - "DEC C++" -#elif defined(Q_CC_EDG) - "Edison Design Group C++" -#elif defined(Q_CC_GHS) - "Green Hills Optimizing C++ Compilers" -#elif defined(Q_CC_GNU) - "GNU C++" -#elif defined(Q_CC_HIGHC) - "MetaWare High C/C++" -#elif defined(Q_CC_HPACC) - "HP aC++" -#elif defined(Q_CC_INTEL) - "Intel C++ for Linux, Intel C++ for Windows" -#elif defined(Q_CC_KAI) - "KAI C++" -#elif defined(Q_CC_MIPS) - "MIPSpro C++" -#elif defined(Q_CC_MSVC) - "Microsoft Visual C/C++, Intel C++ for Windows" -#elif defined(Q_CC_OC) - "CenterLine C++" -#elif defined(Q_CC_PGI) - "Portland Group C++" -#elif defined(Q_CC_SUN) - "Forte Developer, or Sun Studio C++" -#elif defined(Q_CC_SYM) - "Digital Mars C/C++ (used to be Symantec C++)" -#elif defined(Q_CC_USLC) - "SCO OUDK and UDK" -#elif defined(Q_CC_WAT) - "Watcom C++" -#else - "UNKNOWN" -#endif -; - -const QString STR_CURRENT_PLATFORM = QSysInfo::prettyProductName(); -const QString STR_CURRENT_VERSION = QString("%0 (kernel: %1)").arg( - QSysInfo::productVersion(), - QSysInfo::kernelVersion()); -const QString STR_CURRENT_CPU = QSysInfo::currentCpuArchitecture(); -const bool IS_HOST_64BIT = STR_CURRENT_CPU.contains(QLatin1String("64")); - -const int DEFAULT_TIMEOUT_SECS = 30; // ref.: QNetworkConfigurationPrivate::DefaultTimeout -const int DEFAULT_CONCURRENT_FRAGMENTS = 20; - -#endif // GLOBALS_H diff --git a/src/io/filereader.cpp b/src/io/filereader.cpp index 23927c61..87a971e1 100644 --- a/src/io/filereader.cpp +++ b/src/io/filereader.cpp @@ -132,10 +132,10 @@ IFileHandlerPtr FileReader::createReadHandlerHelper(QIODevice *device) if (handler.isNull()) { // no handler: give up. - return IFileHandlerPtr(); + return {}; } if (!handler->canRead()) { - return IFileHandlerPtr(); + return {}; } handler->setDevice(device); return handler; diff --git a/src/io/filereader.h b/src/io/filereader.h index b5ca20d4..9aba74f5 100644 --- a/src/io/filereader.h +++ b/src/io/filereader.h @@ -50,7 +50,7 @@ class FileReader private: /* Device */ - QIODevice *m_device{Q_NULLPTR}; + QIODevice *m_device{nullptr}; IFileHandlerPtr m_handler; bool initHandler(); diff --git a/src/io/filewriter.cpp b/src/io/filewriter.cpp index 3f4047c0..251536d0 100644 --- a/src/io/filewriter.cpp +++ b/src/io/filewriter.cpp @@ -75,8 +75,8 @@ bool FileWriter::canWriteHelper() bool FileWriter::canWrite() { if (auto file = qobject_cast(m_device)) { - const bool remove = !file->isOpen() && !file->exists(); - const bool result = canWriteHelper(); + auto remove = !file->isOpen() && !file->exists(); + auto result = canWriteHelper(); // This looks strange (why remove if it doesn't exist?) but the issue // here is that canWriteHelper will create the file in the process of // checking if the write can succeed. If it subsequently fails, we @@ -140,10 +140,10 @@ IFileHandlerPtr FileWriter::createWriteHandlerHelper(QIODevice *device) handler = Io::findHandlerFromSuffix(suffix); } if (!handler) { - return IFileHandlerPtr(); + return {}; } if (!handler->canWrite()) { - return IFileHandlerPtr(); + return {}; } handler->setDevice(device); return handler; diff --git a/src/io/filewriter.h b/src/io/filewriter.h index 37417984..01940752 100644 --- a/src/io/filewriter.h +++ b/src/io/filewriter.h @@ -51,7 +51,7 @@ class FileWriter private: /* Device */ - QIODevice *m_device{Q_NULLPTR}; + QIODevice *m_device{nullptr}; IFileHandlerPtr m_handler; bool canWriteHelper(); diff --git a/src/io/format.h b/src/io/format.h index 7c1c6a1e..bf57706b 100644 --- a/src/io/format.h +++ b/src/io/format.h @@ -37,7 +37,7 @@ struct FileFormat { if (tr_text == "Text Files") { return QObject::tr("Text Files"); } if (tr_text == "Json Files") { return QObject::tr("Json Files"); } if (tr_text == "Torrent Files") { return QObject::tr("Torrent Files"); } - return QString(); + return {}; } }; @@ -45,7 +45,7 @@ static const FileFormat formats[] = { { "txt", "Text Files", IFileHandlerPtr(new TextHandler()) }, { "json", "Json Files", IFileHandlerPtr(new JsonHandler()) }, { "torrent", "Torrent Files", IFileHandlerPtr(new TorrentHandler()) }, - { Q_NULLPTR, Q_NULLPTR, IFileHandlerPtr() } + { nullptr, nullptr, IFileHandlerPtr() } }; static IFileHandlerPtr findHandlerFromSuffix(const QString &suffix) diff --git a/src/io/ifilehandler.cpp b/src/io/ifilehandler.cpp index 3e1d5503..94c7706e 100644 --- a/src/io/ifilehandler.cpp +++ b/src/io/ifilehandler.cpp @@ -36,6 +36,6 @@ QIODevice *IFileHandler::device() const bool IFileHandler::write(const DownloadEngine &engine) { - Q_UNUSED(engine); + Q_UNUSED(engine) return false; } diff --git a/src/io/ifilehandler.h b/src/io/ifilehandler.h index d4e1ffca..0db1a1c3 100644 --- a/src/io/ifilehandler.h +++ b/src/io/ifilehandler.h @@ -51,7 +51,7 @@ class IFileHandler private: - QIODevice *m_device{Q_NULLPTR}; + QIODevice *m_device{nullptr}; Q_DISABLE_COPY(IFileHandler) }; diff --git a/src/io/jsonhandler.cpp b/src/io/jsonhandler.cpp index 45458739..f10ab6de 100644 --- a/src/io/jsonhandler.cpp +++ b/src/io/jsonhandler.cpp @@ -81,7 +81,7 @@ bool JsonHandler::write(const DownloadEngine &engine) } QJsonObject json; QJsonArray jobsArray; - foreach (auto item, engine.downloadItems()) { + for (auto item : engine.downloadItems()) { QUrl url = item->sourceUrl(); QJsonObject jobObject; diff --git a/src/io/jsonhandler.h b/src/io/jsonhandler.h index 1813f0d6..e702c78a 100644 --- a/src/io/jsonhandler.h +++ b/src/io/jsonhandler.h @@ -24,11 +24,11 @@ class JsonHandler : public IFileHandler public: explicit JsonHandler() = default; - bool canRead() const Q_DECL_OVERRIDE; - bool canWrite() const Q_DECL_OVERRIDE; + bool canRead() const override; + bool canWrite() const override; - bool read(DownloadEngine *engine) Q_DECL_OVERRIDE; - bool write(const DownloadEngine &engine) Q_DECL_OVERRIDE; + bool read(DownloadEngine *engine) override; + bool write(const DownloadEngine &engine) override; private: }; diff --git a/src/io/texthandler.cpp b/src/io/texthandler.cpp index d20565c5..4945dfd6 100644 --- a/src/io/texthandler.cpp +++ b/src/io/texthandler.cpp @@ -79,7 +79,7 @@ bool TextHandler::write(const DownloadEngine &engine) if (!d->isWritable()) { return false; } - foreach (auto item, engine.downloadItems()) { + for (auto item : engine.downloadItems()) { QUrl url = item->sourceUrl(); QByteArray data = url.toString().toUtf8(); out << data << '\n'; diff --git a/src/io/texthandler.h b/src/io/texthandler.h index 4fb0d08b..c9bb898e 100644 --- a/src/io/texthandler.h +++ b/src/io/texthandler.h @@ -24,11 +24,11 @@ class TextHandler : public IFileHandler public: explicit TextHandler() = default; - bool canRead() const Q_DECL_OVERRIDE; - bool canWrite() const Q_DECL_OVERRIDE; + bool canRead() const override; + bool canWrite() const override; - bool read(DownloadEngine *engine) Q_DECL_OVERRIDE; - bool write(const DownloadEngine &engine) Q_DECL_OVERRIDE; + bool read(DownloadEngine *engine) override; + bool write(const DownloadEngine &engine) override; private: }; diff --git a/src/io/torrenthandler.h b/src/io/torrenthandler.h index e701c457..0ae334a7 100644 --- a/src/io/torrenthandler.h +++ b/src/io/torrenthandler.h @@ -24,11 +24,11 @@ class TorrentHandler : public IFileHandler public: explicit TorrentHandler() = default; - bool canRead() const Q_DECL_OVERRIDE; - bool canWrite() const Q_DECL_OVERRIDE; + bool canRead() const override; + bool canWrite() const override; - bool read(DownloadEngine *engine) Q_DECL_OVERRIDE; - bool write(const DownloadEngine &engine) Q_DECL_OVERRIDE; + bool read(DownloadEngine *engine) override; + bool write(const DownloadEngine &engine) override; private: }; diff --git a/src/ipc/constants.h b/src/ipc/constants.h index e2cc9312..0cc57203 100644 --- a/src/ipc/constants.h +++ b/src/ipc/constants.h @@ -62,35 +62,35 @@ * * Example 2 * \code - * QString msg; + * QLatin1StringView msg; * msg = "[IPC_BEGIN] [OPEN_URL] https://www.example.org/2019/12/" [IPC_END]"; * \endcode */ -static const QString C_SHARED_MEMORY_KEY ("org.example.QSharedMemory.DownloadManager"); -static const QString C_SHARED_MEMORY_ACK_REPLY ("0K3Y_B0Y"); +static const QLatin1StringView C_SHARED_MEMORY_KEY ("org.example.QSharedMemory.DownloadManager"); +static const QLatin1StringView C_SHARED_MEMORY_ACK_REPLY ("0K3Y_B0Y"); -static const QString C_PACKET_BEGIN ("[IPC_BEGIN]"); -static const QString C_PACKET_END ("[IPC_END]"); -static const QString C_PACKET_ERROR ("[ERROR]"); +static const QLatin1StringView C_PACKET_BEGIN ("[IPC_BEGIN]"); +static const QLatin1StringView C_PACKET_END ("[IPC_END]"); +static const QLatin1StringView C_PACKET_ERROR ("[ERROR]"); -static const QString C_KEYWORD_CURRENT_URL ("[CURRENT_URL]"); -static const QString C_KEYWORD_LINKS ("[LINKS]"); -static const QString C_KEYWORD_MEDIA ("[MEDIA]"); -static const QString C_KEYWORD_OPEN_URL ("[OPEN_URL]"); -static const QString C_KEYWORD_DOWNLOAD_LINK ("[DOWNLOAD_LINK]"); -static const QString C_KEYWORD_MANAGER ("[MANAGER]"); -static const QString C_KEYWORD_PREFS ("[PREFS]"); +static const QLatin1StringView C_KEYWORD_CURRENT_URL ("[CURRENT_URL]"); +static const QLatin1StringView C_KEYWORD_LINKS ("[LINKS]"); +static const QLatin1StringView C_KEYWORD_MEDIA ("[MEDIA]"); +static const QLatin1StringView C_KEYWORD_OPEN_URL ("[OPEN_URL]"); +static const QLatin1StringView C_KEYWORD_DOWNLOAD_LINK ("[DOWNLOAD_LINK]"); +static const QLatin1StringView C_KEYWORD_MANAGER ("[MANAGER]"); +static const QLatin1StringView C_KEYWORD_PREFS ("[PREFS]"); -static const QString C_KEYWORD_QUICK_LINKS ("[QUICK_LINKS]"); -static const QString C_KEYWORD_QUICK_MEDIA ("[QUICK_MEDIA]"); -static const QString C_KEYWORD_STARTED_PAUSED ("[STARTED_PAUSED]"); +static const QLatin1StringView C_KEYWORD_QUICK_LINKS ("[QUICK_LINKS]"); +static const QLatin1StringView C_KEYWORD_QUICK_MEDIA ("[QUICK_MEDIA]"); +static const QLatin1StringView C_KEYWORD_STARTED_PAUSED ("[STARTED_PAUSED]"); -static const std::string C_STR_CURRENT_URL( C_KEYWORD_CURRENT_URL.toStdString()); -static const std::string C_STR_LINKS( C_KEYWORD_LINKS.toStdString()); -static const std::string C_STR_OPEN_URL( C_KEYWORD_OPEN_URL.toStdString()); -static const std::string C_STR_DOWNLOAD_LINK( C_KEYWORD_DOWNLOAD_LINK.toStdString()); -static const std::string C_STR_ERROR( C_PACKET_ERROR.toStdString()); +static const std::string C_STR_CURRENT_URL( C_KEYWORD_CURRENT_URL.toString().toStdString()); +static const std::string C_STR_LINKS( C_KEYWORD_LINKS.toString().toStdString()); +static const std::string C_STR_OPEN_URL( C_KEYWORD_OPEN_URL.toString().toStdString()); +static const std::string C_STR_DOWNLOAD_LINK( C_KEYWORD_DOWNLOAD_LINK.toString().toStdString()); +static const std::string C_STR_ERROR( C_PACKET_ERROR.toString().toStdString()); static inline QString shm_read(QSharedMemory *sharedMemory) diff --git a/src/ipc/interprocesscommunication.cpp b/src/ipc/interprocesscommunication.cpp index 601e9165..8b96fc19 100644 --- a/src/ipc/interprocesscommunication.cpp +++ b/src/ipc/interprocesscommunication.cpp @@ -92,13 +92,13 @@ bool InterProcessCommunication::isCommandOpenUrl(const QString &message) QString InterProcessCommunication::getCurrentUrl(const QString &message) { - const QStringList resources = message.split(QChar::Space, Qt::SkipEmptyParts); - for (int i = 0; i < resources.count() - 1; ++i) { + auto resources = message.split(QChar::Space, Qt::SkipEmptyParts); + for (auto i = 0; i < resources.count() - 1; ++i) { if (resources.at(i).trimmed() == C_KEYWORD_OPEN_URL) { return resources.at(i+1).trimmed(); } } - return QString(); + return {}; } bool InterProcessCommunication::isCommandDownloadLink(const QString &message) @@ -114,14 +114,14 @@ QString InterProcessCommunication::getDownloadLink(const QString &message) return resources.at(i+1).trimmed(); } } - return QString(); + return {}; } void InterProcessCommunication::parseMessage(const QString &message, Model *model, InterProcessCommunication::Options *options) { - if (model == Q_NULLPTR) { + if (model == nullptr) { return; } if (message.contains(C_PACKET_ERROR, Qt::CaseInsensitive)) { @@ -130,9 +130,9 @@ void InterProcessCommunication::parseMessage(const QString &message, Model *mode Mode mode = None; - const QStringList resources = message.split(QChar::Space, Qt::SkipEmptyParts); + auto resources = message.split(QChar::Space, Qt::SkipEmptyParts); - foreach (auto resource, resources) { + for (auto resource : resources) { auto trimmed = resource.trimmed(); if (trimmed.isEmpty()) { continue; diff --git a/src/ipc/interprocesscommunication.h b/src/ipc/interprocesscommunication.h index 674cfb92..38643b2d 100644 --- a/src/ipc/interprocesscommunication.h +++ b/src/ipc/interprocesscommunication.h @@ -47,7 +47,7 @@ class InterProcessCommunication static bool isCommandDownloadLink(const QString &message); static QString getDownloadLink(const QString &message); - static void parseMessage(const QString &message, Model *model, Options *options = Q_NULLPTR); + static void parseMessage(const QString &message, Model *model, Options *options = nullptr); }; diff --git a/src/main.cpp b/src/main.cpp index 3851ff29..29e3b82b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,9 +14,10 @@ * License along with this program; If not, see . */ -#include "globals.h" #include "mainwindow.h" +#include "version.h" +#include #include #include @@ -25,32 +26,28 @@ /* Enable the type to be used with QVariant. */ Q_DECLARE_METATYPE(QList) -constexpr int msec_message_timeout = 2000; - #ifndef QT_DEBUG void releaseVerboseMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &msg) { - QByteArray localMsg = msg.toLocal8Bit(); switch (type) { - case QtDebugMsg: fprintf(stderr, "Debug: %s\n", localMsg.constData()); break; - case QtInfoMsg: fprintf(stderr, "Info: %s\n", localMsg.constData()); break; - case QtWarningMsg: fprintf(stderr, "Warning: %s\n", localMsg.constData()); break; - case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", localMsg.constData()); break; - case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", localMsg.constData()); break; + case QtDebugMsg: fprintf(stderr, "Debug: %s\n", qPrintable(msg)); break; + case QtInfoMsg: fprintf(stderr, "Info: %s\n", qPrintable(msg)); break; + case QtWarningMsg: fprintf(stderr, "Warning: %s\n", qPrintable(msg)); break; + case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", qPrintable(msg)); break; + case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", qPrintable(msg)); break; } } void releaseDefaultMessageHandler(QtMsgType type, const QMessageLogContext &, const QString &msg) { - QByteArray localMsg = msg.toLocal8Bit(); switch (type) { case QtDebugMsg: // In release mode, ignore debug messages but show fatal and warning. break; - case QtInfoMsg: fprintf(stderr, "Info: %s\n", localMsg.constData()); break; - case QtWarningMsg: fprintf(stderr, "Warning: %s\n", localMsg.constData()); break; - case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", localMsg.constData()); break; - case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", localMsg.constData()); break; + case QtInfoMsg: fprintf(stderr, "Info: %s\n", qPrintable(msg)); break; + case QtWarningMsg: fprintf(stderr, "Warning: %s\n", qPrintable(msg)); break; + case QtCriticalMsg: fprintf(stderr, "Critical: %s\n", qPrintable(msg)); break; + case QtFatalMsg: fprintf(stderr, "Fatal: %s\n", qPrintable(msg)); break; } } #endif @@ -80,6 +77,9 @@ int main(int argc, char *argv[]) parser.process(application); + // Fix missing Title Bar icon on KDE Plasma's Wayland session. + application.setDesktopFileName("downzemall"); + #ifndef QT_DEBUG if (parser.isSet(verboseOption)) { qInstallMessageHandler(releaseVerboseMessageHandler); @@ -87,7 +87,7 @@ int main(int argc, char *argv[]) qInstallMessageHandler(releaseDefaultMessageHandler); } #else - qInstallMessageHandler(Q_NULLPTR); // default handler (show all messages) + qInstallMessageHandler(nullptr); // default handler (show all messages) #endif QString message; @@ -95,7 +95,7 @@ int main(int argc, char *argv[]) message = InterProcessCommunication::readMessageFromLauncher(); } else { const QStringList positionalArguments = parser.positionalArguments(); - foreach (auto positionalArgument, positionalArguments) { + for (auto positionalArgument : positionalArguments) { message += positionalArgument; message += QChar::Space; } @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) if (application.isRunning()) { qWarning("Another instance is running..."); // Rem: Even if is empty, the message is still sent to activate the window. - bool ok = application.sendMessage(message, msec_message_timeout); + bool ok = application.sendMessage(message, MSEC_MESSAGE_TIMEOUT); if (!ok) { qCritical("Message sending failed; the application may be frozen."); } @@ -120,8 +120,8 @@ int main(int argc, char *argv[]) } application.setActivationWindow(&window); - QObject::connect(&application, SIGNAL(messageReceived(const QString&)), - &window, SLOT(handleMessage(const QString&))); + + QObject::connect(&application, SIGNAL(messageReceived(QString)), &window, SLOT(handleMessage(QString))); return QtSingleApplication::exec(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 65601a15..6123b2b2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -18,9 +18,8 @@ #include "ui_mainwindow.h" #include "about.h" -#include "version.h" -#include "globals.h" +#include #include #include #include @@ -86,10 +85,6 @@ # include #endif -constexpr int default_width = 1000; -constexpr int default_height = 700; -constexpr int default_x = 100; -constexpr int default_y = 100; MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) @@ -108,7 +103,7 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) m_streamManager->setSettings(m_settings); - TorrentContext& torrentContext = TorrentContext::getInstance(); + TorrentContext& torrentContext = TorrentContext::getInstance(); torrentContext.setSettings(m_settings); torrentContext.setNetworkManager(m_downloadManager->networkManager()); @@ -146,23 +141,14 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) /* Connect the SceneManager to the MainWindow. */ /* The SceneManager centralizes the changes. */ - connect(m_downloadManager, SIGNAL(jobAppended(DownloadRange)), - this, SLOT(onJobAddedOrRemoved(DownloadRange))); - connect(m_downloadManager, SIGNAL(jobRemoved(DownloadRange)), - this, SLOT(onJobAddedOrRemoved(DownloadRange))); - connect(m_downloadManager, SIGNAL(jobStateChanged(IDownloadItem*)), - this, SLOT(onJobStateChanged(IDownloadItem*))); - connect(m_downloadManager, SIGNAL(jobFinished(IDownloadItem*)), - this, SLOT(onJobFinished(IDownloadItem*))); - connect(m_downloadManager, SIGNAL(jobRenamed(QString, QString, bool)), - this, SLOT(onJobRenamed(QString, QString, bool)), Qt::QueuedConnection); - connect(m_downloadManager, SIGNAL(selectionChanged()), - this, SLOT(onSelectionChanged())); - - - connect(ui->downloadQueueView, SIGNAL(doubleClicked(IDownloadItem*)), - this, SLOT(openFile(IDownloadItem*))); + connect(m_downloadManager, SIGNAL(jobAppended(DownloadRange)), this, SLOT(onJobAddedOrRemoved(DownloadRange))); + connect(m_downloadManager, SIGNAL(jobRemoved(DownloadRange)), this, SLOT(onJobAddedOrRemoved(DownloadRange))); + connect(m_downloadManager, SIGNAL(jobStateChanged(IDownloadItem*)), this, SLOT(onJobStateChanged(IDownloadItem*))); + connect(m_downloadManager, SIGNAL(jobFinished(IDownloadItem*)), this, SLOT(onJobFinished(IDownloadItem*))); + connect(m_downloadManager, SIGNAL(jobRenamed(QString,QString,bool)), this, SLOT(onJobRenamed(QString,QString,bool)), Qt::QueuedConnection); + connect(m_downloadManager, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged())); + connect(ui->downloadQueueView, SIGNAL(doubleClicked(IDownloadItem*)), this, SLOT(openFile(IDownloadItem*))); /* Torrent Context Manager */ connect(&torrentContext, &TorrentContext::changed, this, &MainWindow::onTorrentContextChanged); @@ -188,11 +174,11 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) ui->splitter->setStretchFactor(1, 0); if (!m_settings->isDontShowTutorialEnabled()) { - QTimer::singleShot(250, this, SLOT(showTutorial())); + QTimer::singleShot(TIMEOUT_TUTORIAL, this, SLOT(showTutorial())); } /* Update Checker */ - connect(m_updateChecker, SIGNAL(updateAvailable()), this, SLOT(onUpdateAvailable())); + connect(m_updateChecker, SIGNAL(updateAvailableForConsole()), this, SLOT(onUpdateAvailableForConsole())); m_updateChecker->checkForUpdates(m_settings); } @@ -364,10 +350,10 @@ void MainWindow::createContextMenu() { // delete previous menu if any QMenu *contextMenu = ui->downloadQueueView->contextMenu(); - ui->downloadQueueView->setContextMenu(Q_NULLPTR); + ui->downloadQueueView->setContextMenu(nullptr); if (contextMenu) { delete contextMenu; - contextMenu = Q_NULLPTR; + contextMenu = nullptr; } contextMenu = new QMenu(this); @@ -441,7 +427,7 @@ void MainWindow::propagateToolTips() { // Propagate tooltip to whatsThis and statusTip QList actions = this->findChildren(); - foreach (QAction *action, actions) { + for (auto *action : actions) { if (!action->isSeparator()) { auto str = action->toolTip(); action->setWhatsThis(str); @@ -452,7 +438,7 @@ void MainWindow::propagateToolTips() void MainWindow::propagateIcons() { - const QMap map = { + const QHash hash = { //! [0] File {ui->actionHome , "home"}, @@ -530,7 +516,7 @@ void MainWindow::propagateIcons() // {ui->actionAboutYTDLP , ""} //! [5] }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } /****************************************************************************** @@ -566,7 +552,7 @@ void MainWindow::selectNone() void MainWindow::invertSelection() { QList inverted; - foreach (auto item, m_downloadManager->downloadItems()) { + for (auto item : m_downloadManager->downloadItems()) { if (!m_downloadManager->isSelected(item)) { inverted.append(item); } @@ -867,7 +853,7 @@ void MainWindow::addContent() dialog.setInputMethodHints(Qt::ImhUrlCharactersOnly); dialog.setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); dialog.adjustSize(); - dialog.resize(600, dialog.height()); + dialog.resize(DIALOG_WIDTH, dialog.height()); const int ret = dialog.exec(); const QUrl url = QUrl(dialog.textValue()); @@ -963,21 +949,21 @@ void MainWindow::addUrls(const QString &text) ******************************************************************************/ void MainWindow::resume() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->resume(item); } } void MainWindow::cancel() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->cancel(item); } } void MainWindow::pause() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->pause(item); } } @@ -1014,7 +1000,7 @@ void MainWindow::addDomainSpecificLimit() void MainWindow::forceStart() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { /// todo Maybe run the item instantly (in a higher priority queue?) m_downloadManager->cancel(item); m_downloadManager->resume(item); @@ -1037,14 +1023,14 @@ void MainWindow::showTutorial() dialog.exec(); } -void MainWindow::onUpdateAvailable() +void MainWindow::onUpdateAvailableForConsole() { checkForUpdates(); } void MainWindow::checkForUpdates() { - disconnect(m_updateChecker, SIGNAL(updateAvailable()), this, SLOT(onUpdateAvailable())); + disconnect(m_updateChecker, SIGNAL(updateAvailableForConsole()), this, SLOT(onUpdateAvailableForConsole())); UpdateDialog dialog(m_updateChecker, this); dialog.exec(); } @@ -1120,18 +1106,18 @@ void MainWindow::onTorrentContextChanged() void MainWindow::refreshTitleAndStatus() { - qreal speed = m_downloadManager->totalSpeed(); - QString totalSpeed = speed > 0 - ? QString("~%0").arg(Format::currentSpeedToString(speed)) - : QString(); - - const int completedCount = m_downloadManager->completedJobs().count(); - const int runningCount = m_downloadManager->runningJobs().count(); - const int failedCount = m_downloadManager->failedJobs().count(); - const int count = m_downloadManager->count(); - const int doneCount = completedCount + failedCount; + auto speed = m_downloadManager->totalSpeed(); + QString totalSpeed; + if (speed > 0) { + totalSpeed = QString("~%0").arg(Format::currentSpeedToString(speed)); + } + auto completedCount = m_downloadManager->completedJobs().count(); + auto runningCount = m_downloadManager->runningJobs().count(); + auto failedCount = m_downloadManager->failedJobs().count(); + auto count = m_downloadManager->count(); + auto doneCount = completedCount + failedCount; - const bool torrent = TorrentContext::getInstance().isEnabled(); + auto torrent = TorrentContext::getInstance().isEnabled(); auto windowTitle = QString("%0 %1/%2 - %3 v%4").arg( totalSpeed, @@ -1185,14 +1171,14 @@ void MainWindow::refreshMenus() const bool hasSelection = !m_downloadManager->selection().isEmpty(); const bool hasOnlyOneSelected = m_downloadManager->selection().count() == 1; bool hasOnlyCompletedSelected = hasSelection; - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { if (item->state() != IDownloadItem::Completed) { hasOnlyCompletedSelected = false; continue; } } bool hasAtLeastOneUncompletedSelected = false; - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { if (item->state() != IDownloadItem::Completed) { hasAtLeastOneUncompletedSelected = true; continue; @@ -1201,7 +1187,7 @@ void MainWindow::refreshMenus() bool hasResumableSelection = false; bool hasPausableSelection = false; bool hasCancelableSelection = false; - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { if (item->isResumable()) { hasResumableSelection = true; } @@ -1285,9 +1271,9 @@ void MainWindow::refreshSplitter() if (m_downloadManager->selection().count() == 1) { auto item = m_downloadManager->selection().first(); DownloadTorrentItem *torrentItem = dynamic_cast(item); - ui->torrentWidget->setTorrent(torrentItem ? torrentItem->torrent() : Q_NULLPTR); + ui->torrentWidget->setTorrent(torrentItem ? torrentItem->torrent() : nullptr); } else { - ui->torrentWidget->setTorrent(Q_NULLPTR); + ui->torrentWidget->setTorrent(nullptr); } if (!ui->torrentWidget->isEmpty() /*&& option.showable */) { ui->torrentWidget->show(); @@ -1318,13 +1304,13 @@ void MainWindow::readSettings() { QSettings settings; if ( !isMaximized() ) { - const QPoint defaultPosition(default_x, default_y); - const QSize defaultSize(default_width, default_height); + const QPoint defaultPosition(DEFAULT_X, DEFAULT_Y); + const QSize defaultSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); QPoint position = settings.value("Position", defaultPosition).toPoint(); QSize size = settings.value("Size", defaultSize).toSize(); QRect availableGeometry(0, 0, 0, 0); - foreach (auto screen, QApplication::screens()) { + for (auto screen : QApplication::screens()) { availableGeometry = availableGeometry.united(screen->availableGeometry()); } @@ -1335,11 +1321,7 @@ void MainWindow::readSettings() this->move(position); this->resize(size); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) setWindowState(settings.value("WindowState", 0).value()); -#else - setWindowState((Qt::WindowStates)settings.value("WindowState", 0).toInt() ); -#endif setWorkingDirectory(settings.value("WorkingDirectory").toString()); restoreState(settings.value("WindowToolbarState").toByteArray()); @@ -1387,14 +1369,14 @@ inline QUrl MainWindow::droppedUrl(const QMimeData* mimeData) const auto supposedFilePath = mimeData->text(); return QUrl(supposedFilePath); } - return QUrl(); + return {}; } inline QString MainWindow::fromClipboard() const { const QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); - return mimeData->hasText() ? mimeData->text() : QString(); + return mimeData->hasText() ? mimeData->text() : ""_L1; } inline QUrl MainWindow::urlFromClipboard() const @@ -1429,7 +1411,7 @@ bool MainWindow::saveFile(const QString &path) } this->refreshTitleAndStatus(); this->refreshMenus(); - this->statusBar()->showMessage(tr("File saved"), 2000); + this->statusBar()->showMessage(tr("File saved"), TIMEOUT_STATUSBAR.count()); return true; } @@ -1448,6 +1430,6 @@ bool MainWindow::loadFile(const QString &path) } this->refreshTitleAndStatus(); this->refreshMenus(); - this->statusBar()->showMessage(tr("File loaded"), 5000); + this->statusBar()->showMessage(tr("File loaded"), TIMEOUT_STATUSBAR_LONG.count()); return true; } diff --git a/src/mainwindow.h b/src/mainwindow.h index 831573ce..77cec73b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -49,20 +49,20 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = Q_NULLPTR); - ~MainWindow() Q_DECL_OVERRIDE; + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow() override; bool saveFile(const QString &path); bool loadFile(const QString &path); protected: - void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; - void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; - void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *event) override; + void showEvent(QShowEvent *event) override; + void changeEvent(QEvent *event) override; + void keyPressEvent(QKeyEvent *event) override; - void dragEnterEvent(QDragEnterEvent *event) Q_DECL_OVERRIDE; - void dropEvent(QDropEvent *event) Q_DECL_OVERRIDE; + void dragEnterEvent(QDragEnterEvent *event) override; + void dropEvent(QDropEvent *event) override; public slots: @@ -125,7 +125,7 @@ public slots: void showPreferences(); // Help - void onUpdateAvailable(); + void onUpdateAvailableForConsole(); void checkForUpdates(); void showTutorial(); void about(); @@ -141,18 +141,18 @@ private slots: void onTorrentContextChanged(); private: - Ui::MainWindow *ui; - DownloadManager *m_downloadManager; - StreamManager *m_streamManager; - FileAccessManager *m_fileAccessManager; - Settings *m_settings; - QLabel *m_statusBarLabel; + Ui::MainWindow *ui = nullptr; + DownloadManager *m_downloadManager = nullptr; + StreamManager *m_streamManager = nullptr; + FileAccessManager *m_fileAccessManager = nullptr; + Settings *m_settings = nullptr; + QLabel *m_statusBarLabel = nullptr; #ifdef USE_QT_WINEXTRAS - QWinTaskbarButton *m_winTaskbarButton = Q_NULLPTR; - QWinTaskbarProgress *m_winTaskbarProgress = Q_NULLPTR; + QWinTaskbarButton *m_winTaskbarButton = nullptr; + QWinTaskbarProgress *m_winTaskbarProgress = nullptr; #endif - UpdateChecker *m_updateChecker; - SystemTray *m_systemTray; + UpdateChecker *m_updateChecker = nullptr; + SystemTray *m_systemTray = nullptr; void readSettings(); void writeSettings(); diff --git a/src/version.h b/src/version.h index 8e40d379..6529e3dc 100644 --- a/src/version.h +++ b/src/version.h @@ -17,19 +17,104 @@ #ifndef VERSION_H #define VERSION_H -#include +#include "builddefs.h" + +#include /* CMake */ #ifndef APP_VERSION # include "config.h" #endif -#ifndef BOOST_VERSION_STR -# include "config_3rd.h" -#endif +/* + * Placing a "using namespace .." in C++ headers is generally a bad idea, but + * in the case of Qt::Literals::StringLiterals, it's used everywhere, + * so it shouldn't be an issue. + */ +using namespace Qt::Literals::StringLiterals; + +const QString STR_APPLICATION_NAME{"DownZemAll!"}; +const QString STR_APPLICATION_VERSION{APP_VERSION}; +const QString STR_APPLICATION_DATE{"2020"}; +const QString STR_APPLICATION_AUTHOR{"Sébastien Vavassori"}; +const QString STR_APPLICATION_WEBSITE{"https://github.com/setvisible/DownZemAll"}; +const QString STR_TUTORIAL_WEBSITE{"https://setvisible.github.io/DownZemAll/category/tutorial.html"}; + +const QString STR_GITHUB_OWNER{"setvisible"}; +const QString STR_GITHUB_REPO{"DownZemAll"}; +const QString STR_GITHUB_REPO_ADDRESS{"https://github.com/" % STR_GITHUB_OWNER % "/" % STR_GITHUB_REPO}; +const QString STR_GITHUB_RELEASES_API{"https://api.github.com/repos/" % STR_GITHUB_OWNER % "/" % STR_GITHUB_REPO % "/releases"}; -#define GOOGLE_GUMBO_VERSION_STR "0.10.1" +/* + * Remark: the "Application Organization Name" + * is the string that appears in the Windows registry. + * It should contain only ASCII characters for maximizing + * compatibility with Windows 7/8/10 and following. + */ +const QString STR_APPLICATION_ORGANIZATION{"Sebastien Vavassori"}; + +/* Something like "2017-05-20_15:36:58" */ +const QString STR_APPLICATION_BUILD = + QString("%1-%2-%3_%4:%5:%6") + .arg(BUILD_YEAR, 4, 10, '0'_L1) + .arg(BUILD_MONTH, 2, 10, '0'_L1) + .arg(BUILD_DAY, 2, 10, '0'_L1) + .arg(BUILD_HOUR, 2, 10, '0'_L1) + .arg(BUILD_MIN, 2, 10, '0'_L1) + .arg(BUILD_SEC, 2, 10, '0'_L1); + +/* Compiler Info */ +const QString STR_COMPILER_WORDSIZE{QString::number(QSysInfo::WordSize) % "-bit"_L1}; +const QString STR_COMPILER_BUILD_ABI{QSysInfo::buildAbi()}; +const QString STR_COMPILER_BUILD_CPU{QSysInfo::buildCpuArchitecture()}; + +const QString STR_COMPILER_NAME = +#if defined(Q_CC_BOR) + "Borland/Turbo C++"_L1 +#elif defined(Q_CC_CDS) + "Reliant C++"_L1 +#elif defined(Q_CC_COMEAU) + "Comeau C++"_L1 +#elif defined(Q_CC_DEC) + "DEC C++"_L1 +#elif defined(Q_CC_EDG) + "Edison Design Group C++"_L1 +#elif defined(Q_CC_GHS) + "Green Hills Optimizing C++ Compilers"_L1 +#elif defined(Q_CC_GNU) + "GNU C++"_L1 +#elif defined(Q_CC_HIGHC) + "MetaWare High C/C++"_L1 +#elif defined(Q_CC_HPACC) + "HP aC++"_L1 +#elif defined(Q_CC_INTEL) + "Intel C++ for Linux, Intel C++ for Windows"_L1 +#elif defined(Q_CC_KAI) + "KAI C++"_L1 +#elif defined(Q_CC_MIPS) + "MIPSpro C++"_L1 +#elif defined(Q_CC_MSVC) + "Microsoft Visual C/C++, Intel C++ for Windows"_L1 +#elif defined(Q_CC_OC) + "CenterLine C++"_L1 +#elif defined(Q_CC_PGI) + "Portland Group C++"_L1 +#elif defined(Q_CC_SUN) + "Forte Developer, or Sun Studio C++"_L1 +#elif defined(Q_CC_SYM) + "Digital Mars C/C++ (used to be Symantec C++)"_L1 +#elif defined(Q_CC_USLC) + "SCO OUDK and UDK"_L1 +#elif defined(Q_CC_WAT) + "Watcom C++"_L1 +#else + "UNKNOWN"_L1 +#endif + ; -#define LIBTORRENT_VERSION_STR LIBTORRENT_VERSION +const QString STR_CURRENT_PLATFORM{QSysInfo::prettyProductName()}; +const QString STR_CURRENT_VERSION{QSysInfo::productVersion() % " (kernel: " % QSysInfo::kernelVersion() % ")"}; +const QString STR_CURRENT_CPU{QSysInfo::currentCpuArchitecture()}; +const bool IS_HOST_64BIT = STR_CURRENT_CPU.contains("64"_L1); #endif // VERSION_H diff --git a/src/version_3rd.h b/src/version_3rd.h new file mode 100644 index 00000000..faea59d5 --- /dev/null +++ b/src/version_3rd.h @@ -0,0 +1,29 @@ +/* - DownZemAll! - Copyright (C) 2019-present Sebastien Vavassori + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, see . + */ + +#ifndef VERSION_3RD_H +#define VERSION_3RD_H + +#include +#define LIBTORRENT_VERSION_STR LIBTORRENT_VERSION + +#ifndef BOOST_VERSION_STR +# include "config_3rd.h" +#endif + +#define GOOGLE_GUMBO_VERSION_STR "0.10.1" + +#endif // VERSION_3RD_H diff --git a/src/widgets/advancedsettingswidget.cpp b/src/widgets/advancedsettingswidget.cpp index a72af2c7..1c48bb11 100644 --- a/src/widgets/advancedsettingswidget.cpp +++ b/src/widgets/advancedsettingswidget.cpp @@ -46,13 +46,11 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(QWidget *parent) : QWidget(parent connect(ui->searchLineEdit, &QLineEdit::textChanged, this, &AdvancedSettingsWidget::setFilter); connect(ui->searchClearToolButton, &QToolButton::released, ui->searchLineEdit, &QLineEdit::clear); - connect(ui->modifiedOnlyCheckBox, &QCheckBox::stateChanged, - this, &AdvancedSettingsWidget::showModifiedOnly); + connect(ui->modifiedOnlyCheckBox, &QCheckBox::stateChanged, this, &AdvancedSettingsWidget::showModifiedOnly); /* Context menu */ ui->treeWidget->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, - this, &AdvancedSettingsWidget::showContextMenu); + connect(ui->treeWidget, &QTreeWidget::customContextMenuRequested, this, &AdvancedSettingsWidget::showContextMenu); /* * Workaround to make column 1 only editable: @@ -61,10 +59,8 @@ AdvancedSettingsWidget::AdvancedSettingsWidget(QWidget *parent) : QWidget(parent * 3) Connect QTreeWidget's "doubleClicked" signal to conditional edit slot */ ui->treeWidget->setEditTriggers(QTreeWidget::NoEditTriggers); - connect(ui->treeWidget, &QTreeWidget::doubleClicked, - this, &AdvancedSettingsWidget::edit); - connect(ui->treeWidget, &QTreeWidget::itemChanged, - this, &AdvancedSettingsWidget::format); + connect(ui->treeWidget, &QTreeWidget::doubleClicked, this, &AdvancedSettingsWidget::edit); + connect(ui->treeWidget, &QTreeWidget::itemChanged, this, &AdvancedSettingsWidget::format); populate(); setupPresetToolTip(); @@ -96,11 +92,11 @@ void AdvancedSettingsWidget::changeEvent(QEvent *event) QMap AdvancedSettingsWidget::torrentSettings() const { QMap map; - for (int i = 0, total = ui->treeWidget->topLevelItemCount(); i < total; ++i) { - QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i); + for (auto i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { + auto item = ui->treeWidget->topLevelItem(i); if (isModified(item)) { - QString key = getKey(item); - QVariant value = getValue(item); + auto key = getKey(item); + auto value = getValue(item); map.insert(key, value); } } @@ -167,11 +163,7 @@ void AdvancedSettingsWidget::showContextMenu(const QPoint &/*pos*/) void AdvancedSettingsWidget::edit(const QModelIndex &index) { QModelIndex sibling; -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) sibling = index.siblingAtColumn(1); -#else - sibling = index.sibling(index.row(), 1); -#endif ui->treeWidget->edit(sibling); } @@ -184,13 +176,13 @@ void AdvancedSettingsWidget::editCurrent() ******************************************************************************/ void AdvancedSettingsWidget::format(QTreeWidgetItem *item, int /*column*/) { - QBrush brush = palette().text(); - QFont fnt = font(); + auto brush = palette().text(); + auto fnt = font(); if (isModified(item)) { brush.setColor(Qt::red); fnt.setBold(true); } - for (int col : {0, 1}) { + for (auto col : {0, 1}) { item->setForeground(col, brush); item->setFont(col, fnt); } @@ -200,7 +192,7 @@ void AdvancedSettingsWidget::format(QTreeWidgetItem *item, int /*column*/) ******************************************************************************/ void AdvancedSettingsWidget::resetSelected() { - foreach (auto item, ui->treeWidget->selectedItems()) { + for (auto item : ui->treeWidget->selectedItems()) { resetToDefaultValue(item); } } @@ -226,18 +218,18 @@ void AdvancedSettingsWidget::showModifiedOnly(int /*state*/) void AdvancedSettingsWidget::filter() { - const QString &searchText = ui->searchLineEdit->text(); - const bool mustBeFound = !searchText.isEmpty(); - const bool mustBeModified = ui->modifiedOnlyCheckBox->isChecked(); + auto searchText = ui->searchLineEdit->text(); + auto mustBeFound = !searchText.isEmpty(); + auto mustBeModified = ui->modifiedOnlyCheckBox->isChecked(); - for (int i = 0, total = ui->treeWidget->topLevelItemCount(); i < total; ++i) { - QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i); - const QString text = item->data(0, Qt::DisplayRole).toString(); - const bool isFound = text.contains(searchText, Qt::CaseInsensitive); + for (auto i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { + auto item = ui->treeWidget->topLevelItem(i); + auto text = item->data(0, Qt::DisplayRole).toString(); + auto isFound = text.contains(searchText, Qt::CaseInsensitive); - const bool found = !mustBeFound || isFound; - const bool modified = !mustBeModified || isModified(item); - const bool visible = found && modified; + auto found = !mustBeFound || isFound; + auto modified = !mustBeModified || isModified(item); + auto visible = found && modified; item->setHidden(!visible); } } @@ -261,8 +253,8 @@ void AdvancedSettingsWidget::setPresetHighPerf() void AdvancedSettingsWidget::setPreset(const QList ¶ms) { - foreach (auto param, params) { - QTreeWidgetItem* item = findItem(param.key); + for (auto param : params) { + auto item = findItem(param.key); if (item) { setValue(item, param.value); } @@ -277,9 +269,8 @@ void AdvancedSettingsWidget::populate() QSignalBlocker blocker(this); ui->treeWidget->clear(); - const QList ¶ms - = TorrentContext::getInstance().allSettingsKeysAndValues(); - foreach (auto param, params) { + auto params = TorrentContext::getInstance().allSettingsKeysAndValues(); + for (auto param : params) { auto item = new QTreeWidgetItem(ui->treeWidget); setKey(item, param.key, param.displayKey); setValue(item, param.value); @@ -317,7 +308,7 @@ inline QVariant AdvancedSettingsWidget::getValue(const QTreeWidgetItem *item) co inline void AdvancedSettingsWidget::setValue(QTreeWidgetItem *item, const QVariant &value) { if (item) { - const QVariant oldValue = getValue(item); + auto oldValue = getValue(item); if (oldValue.isNull() || !oldValue.isValid() || oldValue != value) { item->setData(1, Qt::DisplayRole, value); emit changed(); @@ -344,14 +335,14 @@ inline void AdvancedSettingsWidget::resetToDefaultValue(QTreeWidgetItem *item) ******************************************************************************/ inline QTreeWidgetItem* AdvancedSettingsWidget::findItem(const QString &key) const { - for (int i = 0, total = ui->treeWidget->topLevelItemCount(); i < total; ++i) { - QTreeWidgetItem* item = ui->treeWidget->topLevelItem(i); + for (auto i = 0; i < ui->treeWidget->topLevelItemCount(); ++i) { + auto item = ui->treeWidget->topLevelItem(i); if (key == getKey(item)) { return item; } } qWarning("Can't find setting key '%s'.", key.toLatin1().data()); - return Q_NULLPTR; + return nullptr; } /****************************************************************************** @@ -365,7 +356,7 @@ void AdvancedSettingsWidget::setupPresetToolTip() }; QString tooltip; tooltip += ""; - foreach (auto preset, presets) { + for (auto preset : presets) { tooltip += "

        " "- " diff --git a/src/widgets/advancedsettingswidget.h b/src/widgets/advancedsettingswidget.h index 30d3c051..0e8771ee 100644 --- a/src/widgets/advancedsettingswidget.h +++ b/src/widgets/advancedsettingswidget.h @@ -38,8 +38,8 @@ class AdvancedSettingsWidget : public QWidget KeyType }; - explicit AdvancedSettingsWidget(QWidget *parent = Q_NULLPTR); - ~AdvancedSettingsWidget() Q_DECL_OVERRIDE; + explicit AdvancedSettingsWidget(QWidget *parent = nullptr); + ~AdvancedSettingsWidget() override; QMap torrentSettings() const; void setTorrentSettings(const QMap &map); @@ -51,7 +51,7 @@ class AdvancedSettingsWidget : public QWidget void changed(); protected: - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void changeEvent(QEvent *event) override; private slots: void setPresetDefault(); @@ -68,7 +68,7 @@ private slots: void format(QTreeWidgetItem *item, int column); private: - Ui::AdvancedSettingsWidget *ui; + Ui::AdvancedSettingsWidget *ui = nullptr; void restylizeUi(); diff --git a/src/widgets/autoclosedialog.cpp b/src/widgets/autoclosedialog.cpp index b4c2295b..6ed86c01 100644 --- a/src/widgets/autoclosedialog.cpp +++ b/src/widgets/autoclosedialog.cpp @@ -38,12 +38,12 @@ AutoCloseDialog::AutoCloseDialog(QFrame *content, QWidget *parent) : QDialog(par layout->addWidget(content); setLayout(layout); - QRect rect = geometry(); - const QSize minAcceptableSize = QLayout::closestAcceptableSize(this, QSize(0,0)); + auto rect = geometry(); + auto minAcceptableSize = QLayout::closestAcceptableSize(this, QSize(0,0)); rect.setSize(minAcceptableSize); if (parent) { // aligned to parent widget - const QPoint parentTopRight = parent->mapToGlobal(QPoint(parent->width() - 5, -5)); + auto parentTopRight = parent->mapToGlobal(QPoint(parent->width() - 5, -5)); rect.moveBottomRight(parentTopRight); } setGeometry(rect); diff --git a/src/widgets/autoclosedialog.h b/src/widgets/autoclosedialog.h index f5290f0d..a11863bc 100644 --- a/src/widgets/autoclosedialog.h +++ b/src/widgets/autoclosedialog.h @@ -26,10 +26,10 @@ class AutoCloseDialog : public QDialog Q_OBJECT public: - explicit AutoCloseDialog(QFrame *content, QWidget *parent = Q_NULLPTR); + explicit AutoCloseDialog(QFrame *content, QWidget *parent = nullptr); protected: - void leaveEvent(QEvent *event) Q_DECL_OVERRIDE; + void leaveEvent(QEvent *event) override; }; #endif // WIDGETS_AUTO_CLOSE_DIALOG_H diff --git a/src/widgets/checkableitemdelegate.cpp b/src/widgets/checkableitemdelegate.cpp index 34b3d269..a8abe808 100644 --- a/src/widgets/checkableitemdelegate.cpp +++ b/src/widgets/checkableitemdelegate.cpp @@ -16,6 +16,7 @@ #include "checkableitemdelegate.h" +#include #include #include @@ -25,18 +26,11 @@ #include #include -constexpr int checkbox_size = 12; -constexpr int checkbox_width = 16; -constexpr int thumbnail_width = 16; static QModelIndex getSiblingAtColumn(const QModelIndex &index, int acolumn) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) return index.siblingAtColumn(acolumn); -#else - return index.sibling(index.row(), acolumn); -#endif } /*! @@ -86,7 +80,7 @@ void CheckableItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem QStyleOptionButton button; button.rect = myOption.rect; button.palette = myOption.palette; - button.iconSize = QSize(checkbox_size, checkbox_size); + button.iconSize = QSize(CHECKBOX_SIZE, CHECKBOX_SIZE); button.icon = m_checkIcon; button.features |= QStyleOptionButton::Flat; button.state |= checked ? QStyle::State_Enabled : QStyle::State_None; // hack @@ -105,12 +99,12 @@ QSize CheckableItemDelegate::sizeHint(const QStyleOptionViewItem &option, const int CheckableItemDelegate::widthHint() { - return checkbox_width; + return CHECKBOX_WIDTH; } int CheckableItemDelegate::thumbnailHint() { - return thumbnail_width; + return THUMBNAIL_WIDTH; } /****************************************************************************** diff --git a/src/widgets/checkableitemdelegate.h b/src/widgets/checkableitemdelegate.h index 1ba27ec6..64ab9531 100644 --- a/src/widgets/checkableitemdelegate.h +++ b/src/widgets/checkableitemdelegate.h @@ -24,19 +24,18 @@ class CheckableItemDelegate : public QStyledItemDelegate Q_OBJECT public: - explicit CheckableItemDelegate(QObject *parent = Q_NULLPTR); + explicit CheckableItemDelegate(QObject *parent = nullptr); // painting - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; static int widthHint(); static int thumbnailHint(); // editing - bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) Q_DECL_OVERRIDE; + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; private: QIcon m_checkIcon; diff --git a/src/widgets/checkabletableview.cpp b/src/widgets/checkabletableview.cpp index 7aa4e97b..a20a2fce 100644 --- a/src/widgets/checkabletableview.cpp +++ b/src/widgets/checkabletableview.cpp @@ -16,6 +16,7 @@ #include "checkabletableview.h" +#include #include #include @@ -24,10 +25,6 @@ #include #include -constexpr int vertical_header_width = 22; -constexpr int column_default_width = 100; -constexpr int column_max_width = 1000; - CheckableTableView::CheckableTableView(QWidget *parent) : QTableView(parent) { @@ -43,21 +40,19 @@ CheckableTableView::CheckableTableView(QWidget *parent) : QTableView(parent) setAlternatingRowColors(false); setMidLineWidth(3); - QHeaderView *vHeader = verticalHeader(); + auto vHeader = verticalHeader(); vHeader->setSectionResizeMode(QHeaderView::Fixed); - vHeader->setDefaultSectionSize(vertical_header_width); + vHeader->setDefaultSectionSize(VERTICAL_HEADER_WIDTH); vHeader->setVisible(false); - QHeaderView *hHeader = horizontalHeader(); + auto hHeader = horizontalHeader(); hHeader->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); hHeader->setHighlightSections(false); - connect(hHeader, SIGNAL(sectionCountChanged(int,int)), - this, SLOT(onSectionCountChanged(int,int))); + connect(hHeader, SIGNAL(sectionCountChanged(int,int)), this, SLOT(onSectionCountChanged(int,int))); setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenu(const QPoint &))); + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); } /****************************************************************************** @@ -75,8 +70,8 @@ QList CheckableTableView::columnWidths() const Q_ASSERT(model); QList widths; if (model) { - for (int column = 0; column < model->columnCount(); ++column) { - const int width = columnWidth(column); + for (auto column = 0; column < model->columnCount(); ++column) { + auto width = columnWidth(column); widths.append(width); } } @@ -88,17 +83,17 @@ void CheckableTableView::setColumnWidths(const QList &widths) QAbstractItemModel *model = this->model(); Q_ASSERT(model); if (model) { - for (int column = 0; column < model->columnCount(); ++column) { + for (auto column = 0; column < model->columnCount(); ++column) { if (column == 0) { setColumnWidth(column, CheckableItemDelegate::widthHint()); } else if (column > 0 && column < widths.count()) { - int width = widths.at(column); - if (width < 0 || width > column_max_width) { - width = column_default_width; + auto width = widths.at(column); + if (width < 0 || width > COLUMN_MAX_WIDTH) { + width = COLUMN_DEFAULT_WIDTH; } setColumnWidth(column, width); } else { - setColumnWidth(column, column_default_width); + setColumnWidth(column, COLUMN_DEFAULT_WIDTH); } } } @@ -171,7 +166,7 @@ void CheckableTableView::showContextMenu(const QPoint &/*pos*/) ******************************************************************************/ void CheckableTableView::checkSelected() { - foreach (auto index, selectedIndexesAtColumn(0)) { + for (auto index : selectedIndexesAtColumn(0)) { auto model = const_cast(index.model()); model->setData(index, true, CheckableTableModel::CheckStateRole); } @@ -179,7 +174,7 @@ void CheckableTableView::checkSelected() void CheckableTableView::uncheckSelected() { - foreach (auto index, selectedIndexesAtColumn(0)) { + for (auto index : selectedIndexesAtColumn(0)) { auto model = const_cast(index.model()); model->setData(index, false, CheckableTableModel::CheckStateRole); } @@ -187,8 +182,8 @@ void CheckableTableView::uncheckSelected() void CheckableTableView::toggleCheck() { - foreach (auto index, selectedIndexesAtColumn(0)) { - const bool selected = index.model()->data(index, CheckableTableModel::CheckStateRole).toBool(); + for (auto index : selectedIndexesAtColumn(0)) { + auto selected = index.model()->data(index, CheckableTableModel::CheckStateRole).toBool(); auto model = const_cast(index.model()); model->setData(index, !selected, CheckableTableModel::CheckStateRole); } @@ -198,16 +193,16 @@ void CheckableTableView::selectFiltered() { selectionModel()->clearSelection(); - const int rowCount = model()->rowCount(); - const int colCount = model()->columnCount(); - for (int i = 0; i < rowCount; ++i) { + auto rowCount = model()->rowCount(); + auto colCount = model()->columnCount(); + for (auto i = 0; i < rowCount; ++i) { - const QModelIndex &index = model()->index(i, 0); - const bool selected = index.model()->data(index, CheckableTableModel::CheckStateRole).toBool(); + auto index = model()->index(i, 0); + auto selected = index.model()->data(index, CheckableTableModel::CheckStateRole).toBool(); if (selected) { - for (int j = 0; j < colCount; ++j) { - const QModelIndex &selectedIndex = model()->index(i, j); + for (auto j = 0; j < colCount; ++j) { + auto selectedIndex = model()->index(i, j); selectionModel()->select(selectedIndex, QItemSelectionModel::Select); } } @@ -216,11 +211,11 @@ void CheckableTableView::selectFiltered() void CheckableTableView::invertSelection() { - const int rowCount = model()->rowCount(); - const int colCount = model()->columnCount(); - for (int i = 0; i < rowCount; ++i) { - for (int j = 0; j < colCount; ++j) { - const QModelIndex &index = model()->index(i, j); + auto rowCount = model()->rowCount(); + auto colCount = model()->columnCount(); + for (auto i = 0; i < rowCount; ++i) { + for (auto j = 0; j < colCount; ++j) { + auto index = model()->index(i, j); selectionModel()->select(index, QItemSelectionModel::Toggle); } } @@ -231,7 +226,7 @@ void CheckableTableView::invertSelection() QModelIndexList CheckableTableView::selectedIndexesAtColumn(int column) { QModelIndexList indexes; - foreach (auto index, selectionModel()->selectedIndexes()) { + for (auto index : selectionModel()->selectedIndexes()) { if (index.column() == column) { indexes.append(index); } diff --git a/src/widgets/checkabletableview.h b/src/widgets/checkabletableview.h index 9eb49d4a..d7ee222e 100644 --- a/src/widgets/checkabletableview.h +++ b/src/widgets/checkabletableview.h @@ -28,7 +28,7 @@ class CheckableTableView : public QTableView Q_OBJECT public: explicit CheckableTableView(QWidget *parent); - ~CheckableTableView() Q_DECL_OVERRIDE = default; + ~CheckableTableView() override = default; void setContextMenuCallback(const std::function &callback); diff --git a/src/widgets/combobox.cpp b/src/widgets/combobox.cpp index da6da0f5..4221df17 100644 --- a/src/widgets/combobox.cpp +++ b/src/widgets/combobox.cpp @@ -16,6 +16,7 @@ #include "combobox.h" +#include #include #include #include @@ -23,7 +24,6 @@ #include -constexpr int max_history_count = 10; /*! * \class ComboBox @@ -36,7 +36,7 @@ constexpr int max_history_count = 10; ComboBox::ComboBox(QWidget *parent) : QComboBox(parent) { setDuplicatesEnabled(false); - setMaxCount(max_history_count); + setMaxCount(MAX_HISTORY_COUNT); connect(this, SIGNAL(currentTextChanged(QString)), this, SLOT(onCurrentTextChanged(QString))); connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); @@ -63,7 +63,7 @@ void ComboBox::setHistory(const QStringList &history) { auto text = currentText(); clear(); - int i = qMin(max_history_count, history.count()); + auto i = qMin(static_cast(MAX_HISTORY_COUNT), history.count()); while (i > 0) { i--; auto item = history.at(i); @@ -84,7 +84,7 @@ void ComboBox::addToHistory(const QString &text) void ComboBox::removeFromHistory(const QString &text) { - int i = count(); + auto i = count(); while (i > 0) { i--; if (itemText(i) == text) { @@ -114,7 +114,7 @@ void ComboBox::setCurrentText(const QString &text) ******************************************************************************/ bool ComboBox::isInputValid() const { - return m_inputValidityPtr == Q_NULLPTR || m_inputValidityPtr(this->currentText()); + return m_inputValidityPtr == nullptr || m_inputValidityPtr(this->currentText()); } /** @@ -124,7 +124,7 @@ bool ComboBox::isInputValid() const * \li If it returns true, the combobox hightlights an error. * \li If it returns false, the combobox doesn't hightlight any error. * - * To disable the coloration, just pass a null pointer (Q_NULLPTR) as argument, + * To disable the coloration, just pass a null pointer (nullptr) as argument, * or a functor to a method that always returns false. * * @param functor The callback method functor, or null. @@ -163,10 +163,10 @@ void ComboBox::onCurrentIndexChanged(int /*index*/) ******************************************************************************/ void ComboBox::showContextMenu(const QPoint &/*pos*/) { - QMenu *contextMenu = lineEdit()->createStandardContextMenu(); + auto contextMenu = lineEdit()->createStandardContextMenu(); contextMenu->addSeparator(); - QAction *clearAction = contextMenu->addAction(tr("Clear History")); + auto clearAction = contextMenu->addAction(tr("Clear History")); connect(clearAction, SIGNAL(triggered()), this, SLOT(clearHistory())); contextMenu->exec(QCursor::pos()); @@ -175,7 +175,7 @@ void ComboBox::showContextMenu(const QPoint &/*pos*/) void ComboBox::clearHistory() { - const QString text = currentText(); + auto text = currentText(); clear(); setCurrentText(text); } @@ -187,6 +187,6 @@ inline void ComboBox::colorize() if (!isInputValid()) { QComboBox::setStyleSheet(QLatin1String("QComboBox { background-color: palette(link); }")); } else { - QComboBox::setStyleSheet(QString()); + QComboBox::setStyleSheet({}); } } diff --git a/src/widgets/combobox.h b/src/widgets/combobox.h index 86a0edd4..8a19226e 100644 --- a/src/widgets/combobox.h +++ b/src/widgets/combobox.h @@ -26,8 +26,8 @@ class ComboBox : public QComboBox Q_OBJECT public: - explicit ComboBox(QWidget *parent = Q_NULLPTR); - ~ComboBox() Q_DECL_OVERRIDE = default; + explicit ComboBox(QWidget *parent = nullptr); + ~ComboBox() override = default; QStringList history() const; void setHistory(const QStringList &history); @@ -51,7 +51,7 @@ private slots: void showContextMenu(const QPoint &pos); private: - InputValidityPtr m_inputValidityPtr = Q_NULLPTR; + InputValidityPtr m_inputValidityPtr = nullptr; inline void colorize(); }; diff --git a/src/widgets/customstyle.cpp b/src/widgets/customstyle.cpp index 9cb129c9..d5c38ba4 100644 --- a/src/widgets/customstyle.cpp +++ b/src/widgets/customstyle.cpp @@ -16,6 +16,7 @@ #include "customstyle.h" +#include #include #include #include @@ -26,8 +27,6 @@ #include #include -constexpr int icon_size = 16; -constexpr int icon_width = 19; /*! @@ -54,7 +53,7 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, case CE_ProgressBar: if (auto pb = qstyleoption_cast(opt)) { - bool hasIcon = !pb->icon.isNull(); + auto hasIcon = !pb->icon.isNull(); QPalette::ColorGroup cg; QPalette::ColorRole cr; @@ -74,17 +73,17 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, } /* Draw the selection background */ - QColor bgColor = pb->palette.color(cg, cr); + auto bgColor = pb->palette.color(cg, cr); p->setPen(Qt::NoPen); p->setBrush(bgColor); p->drawRect(pb->rect); /* Draw the icon */ if (hasIcon) { - int size = icon_size; - int margin = (qMax(size, pb->rect.height()) - size ) / 2; - QRect iconRect = QRect(pb->rect.x() + margin , pb->rect.y() + margin, size, size); - p->drawPixmap(iconRect, pb->icon.pixmap(icon_size)); + auto size = ICON_SIZE; + auto margin = (qMax(size, pb->rect.height()) - size ) / 2; + auto iconRect = QRect(pb->rect.x() + margin , pb->rect.y() + margin, size, size); + p->drawPixmap(iconRect, pb->icon.pixmap(ICON_SIZE)); } /* Draw the progress bar */ @@ -96,7 +95,7 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, frameRect.setTop(frameRect.top() + marginV); frameRect.setBottom(frameRect.bottom() - marginV); if (hasIcon) { - frameRect.setLeft(frameRect.left() + marginH + icon_width); + frameRect.setLeft(frameRect.left() + marginH + ICON_WIDTH); } else { frameRect.setLeft(frameRect.left() + marginH); } @@ -111,11 +110,11 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, auto maximum = qint64(pb->maximum); auto progress = qint64(pb->progress); - QColor color = pb->color; + auto color = pb->color; QBrush brush; const int margin = 2; - QRect indicatorRect = frameRect; + auto indicatorRect = frameRect; indicatorRect.setLeft(indicatorRect.left() + margin); indicatorRect.setRight(indicatorRect.right() + 1 - margin); @@ -124,23 +123,23 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, // Top bar: Detailed segments { - QRect segmentRect = indicatorRect; + auto segmentRect = indicatorRect; segmentRect.setTop(segmentRect.top() + margin); segmentRect.setBottom(segmentRect.bottom() + 1 - margin - indicatorBarHeight); - QBitArray segments = pb->segments; - int size = segments.size(); + auto segments = pb->segments; + auto size = segments.size(); QImage segmentImage(qMax(1, size), 1, QImage::Format_RGB32); segmentImage.fill(s_lightGrey); - QRgb rgb = color.rgb(); - for (int i = 0; i < size; ++i) { + auto rgb = color.rgb(); + for (auto i = 0; i < size; ++i) { if (segments.testBit(i)) { segmentImage.setPixel(i, 0, rgb); } } - QPixmap segmentPixmap = QPixmap::fromImage(segmentImage); - QPixmap scaled = segmentPixmap.scaled( + auto segmentPixmap = QPixmap::fromImage(segmentImage); + auto scaled = segmentPixmap.scaled( segmentRect.size(), Qt::IgnoreAspectRatio, Qt::FastTransformation); @@ -149,7 +148,7 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, } // Bottom bar: Progress indicator bar - int bottom = indicatorRect.bottom() + 1 - margin; + auto bottom = indicatorRect.bottom() + 1 - margin; indicatorRect.setTop(bottom - indicatorBarHeight); indicatorRect.setBottom(bottom); @@ -159,17 +158,17 @@ void CustomStyle::drawControl(ControlElement element, const QStyleOption *opt, } if (progress < 0 || (minimum == 0 && maximum == 0)) { - QRgb rgb = color.rgb(); - QImage textureImage = m_textureImage; + auto rgb = color.rgb(); + auto textureImage = m_textureImage; textureImage.setColor(1, rgb); - QPixmap pixmap = QPixmap::fromImage(textureImage); + auto pixmap = QPixmap::fromImage(textureImage); brush.setTexture(pixmap); } else { auto p_v = qreal(progress - minimum); auto t_s = (maximum - minimum) ? qreal(maximum - minimum) : qreal(1); auto r = qreal(p_v / t_s); - int w = qMax(qCeil(r * indicatorRect.width()), 1); + auto w = static_cast(qMax(qCeil(r * indicatorRect.width()), 1)); indicatorRect.setWidth(w); brush.setStyle(Qt::SolidPattern); brush.setColor(color); diff --git a/src/widgets/customstyle.h b/src/widgets/customstyle.h index 86bf713e..20ab20b5 100644 --- a/src/widgets/customstyle.h +++ b/src/widgets/customstyle.h @@ -23,12 +23,11 @@ class CustomStyle : public QProxyStyle { public: - CustomStyle(QStyle *style = Q_NULLPTR); + CustomStyle(QStyle *style = nullptr); CustomStyle(const QString &key); - ~CustomStyle() Q_DECL_OVERRIDE = default; + ~CustomStyle() override = default; - void drawControl(ControlElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget = Q_NULLPTR) const Q_DECL_OVERRIDE; + void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override; private: QImage m_textureImage; diff --git a/src/widgets/downloadqueueview.cpp b/src/widgets/downloadqueueview.cpp index e98d5ce2..e707ba1c 100644 --- a/src/widgets/downloadqueueview.cpp +++ b/src/widgets/downloadqueueview.cpp @@ -16,6 +16,7 @@ #include "downloadqueueview_p.h" +#include #include #include #include @@ -37,26 +38,6 @@ #include #include -constexpr int col_0_file_name = 0; -constexpr int col_1_website_domain = 1; -constexpr int col_2_progress_bar = 2; -constexpr int col_3_percent = 3; -constexpr int col_4_size = 4; -constexpr int col_5_estimated_time = 5; -constexpr int col_6_speed = 6; -// constexpr int col_7_segments = 7; /* hidden */ -// constexpr int col_8_mask = 8; /* hidden */ -// constexpr int col_9_save_path = 9; /* hidden */ -// constexpr int col_10_checksum = 10; /* hidden */ - -constexpr int column_default_width = 100; -constexpr int column_0_default_width = 300; -constexpr int row_default_height = 22; - -constexpr int min_progress = 0; -constexpr int max_progress = 100; -constexpr int version_marker = 0xff; - QueueView::QueueView(QWidget *parent) : QTreeWidget(parent) @@ -86,11 +67,11 @@ void QueueView::mouseMoveEvent(QMouseEvent *event) < QApplication::startDragDistance()) { return; } - const QList queueItems = toQueueItem(selectedItems()); + auto queueItems = toQueueItem(selectedItems()); QPixmap pixmap; QList urls; - foreach (auto queueItem, queueItems) { + for (auto queueItem : queueItems) { auto url = urlFrom(queueItem); if (!url.isEmpty()) { if (pixmap.isNull()) { @@ -111,7 +92,7 @@ void QueueView::mouseMoveEvent(QMouseEvent *event) Qt::DropAction dropAction = drag->exec(Qt::MoveAction); if (dropAction == Qt::MoveAction) { - foreach (auto queueItem, queueItems) { + for (auto queueItem : queueItems) { emit dropped(queueItem); } } @@ -120,7 +101,7 @@ void QueueView::mouseMoveEvent(QMouseEvent *event) QList QueueView::toQueueItem(const QList &items) const { QList queueItems; - foreach (auto item, items) { + for (auto item : items) { auto queueItem = dynamic_cast(item); if (queueItem) queueItems << queueItem; @@ -131,18 +112,17 @@ QList QueueView::toQueueItem(const QList &items) QUrl QueueView::urlFrom(const QueueItem *queueItem) const { if (!queueItem) - return QUrl(); + return {}; const AbstractDownloadItem* downloadItem = queueItem->downloadItem(); if (!downloadItem) - return QUrl(); + return {}; const QFileInfo fi(downloadItem->localFullFileName()); if (!fi.exists()) - return QUrl(); + return {}; - const QUrl url = QUrl::fromLocalFile(downloadItem->localFullFileName()); - return url; + return QUrl::fromLocalFile(downloadItem->localFullFileName()); } /****************************************************************************** @@ -155,22 +135,17 @@ class QueueViewItemDelegate : public QStyledItemDelegate Q_OBJECT public: - explicit QueueViewItemDelegate(QObject *parent = Q_NULLPTR); + explicit QueueViewItemDelegate(QObject *parent = nullptr); // painting - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index ) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; // editing - QWidget *createEditor(QWidget *parent, - const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE; + void setEditorData(QWidget *editor, const QModelIndex &index) const override; - void updateEditorGeometry(QWidget *editor, - const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override; void restylizeUi(); @@ -197,11 +172,11 @@ QueueViewItemDelegate::QueueViewItemDelegate(QObject *parent) void QueueViewItemDelegate::restylizeUi() { - m_idleIcon = QIcon(); - m_resumeIcon = QIcon(); - m_pauseIcon = QIcon(); - m_stopIcon = QIcon(); - m_completedIcon = QIcon(); + m_idleIcon = {}; + m_resumeIcon = {}; + m_pauseIcon = {}; + m_stopIcon = {}; + m_completedIcon = {}; m_idleIcon.addPixmap(QIcon::fromTheme("play-idle").pixmap(16), QIcon::Normal, QIcon::On); m_resumeIcon.addPixmap(QIcon::fromTheme("play-resume").pixmap(16), QIcon::Normal, QIcon::On); @@ -210,8 +185,10 @@ void QueueViewItemDelegate::restylizeUi() m_completedIcon.addPixmap(QIcon::fromTheme("remove-completed").pixmap(16), QIcon::Normal, QIcon::On); } -void QueueViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index ) const +void QueueViewItemDelegate::paint( + QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index ) const { QStyleOptionViewItem myOption = option; initStyleOption(&myOption, index); @@ -225,7 +202,7 @@ void QueueViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem myOption.palette.setColor(QPalette::All, QPalette::Highlight, s_lightBlue); myOption.palette.setColor(QPalette::All, QPalette::HighlightedText, s_black); - if (index.column() == col_0_file_name) { + if (index.column() == COL_0_FILE_NAME) { const QUrl url(myOption.text); const QPixmap pixmap = MimeDatabase::fileIcon(url, 16); @@ -237,9 +214,9 @@ void QueueViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem QStyledItemDelegate::paint(painter, myOption, index); - } else if (index.column() == col_2_progress_bar) { + } else if (index.column() == COL_2_PROGRESS_BAR) { - const int progress = index.data(QueueItem::ProgressRole).toInt(); + auto progress = index.data(QueueItem::ProgressRole).toInt(); auto state = static_cast(index.data(QueueItem::StateRole).toInt()); CustomStyleOptionProgressBar progressBarOption; @@ -247,8 +224,8 @@ void QueueViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = myOption.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); - progressBarOption.minimum = min_progress; - progressBarOption.maximum = max_progress; + progressBarOption.minimum = MIN_PROGRESS; + progressBarOption.maximum = MAX_PROGRESS; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = false; progressBarOption.palette = myOption.palette; @@ -262,15 +239,15 @@ void QueueViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem } } -QWidget* QueueViewItemDelegate::createEditor(QWidget *parent, - const QStyleOptionViewItem &/*option*/, - const QModelIndex &index) const +QWidget* QueueViewItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const { + Q_UNUSED(option) + if (!index.isValid()) - return Q_NULLPTR; + return nullptr; - if (index.column() != col_0_file_name) - return Q_NULLPTR; + if (index.column() != COL_0_FILE_NAME) + return nullptr; auto editor = new QLineEdit(parent); editor->setAutoFillBackground(true); @@ -287,9 +264,10 @@ void QueueViewItemDelegate::setEditorData(QWidget *editor, const QModelIndex &in } } -void QueueViewItemDelegate::updateEditorGeometry(QWidget *editor, - const QStyleOptionViewItem &option, - const QModelIndex &/*index*/) const +void QueueViewItemDelegate::updateEditorGeometry( + QWidget *editor, + const QStyleOptionViewItem &option, + const QModelIndex &/*index*/) const { editor->setGeometry(option.rect); } @@ -357,7 +335,7 @@ QIcon QueueViewItemDelegate::stateIcon(IDownloadItem::State state) const Q_UNREACHABLE(); break; } - return QIcon(); + return {}; } /****************************************************************************** @@ -367,7 +345,7 @@ QueueItem::QueueItem(AbstractDownloadItem *downloadItem, QTreeWidget *view) , QTreeWidgetItem(view, QTreeWidgetItem::UserType) , m_downloadItem(downloadItem) { - this->setSizeHint(col_2_progress_bar, QSize(column_default_width, row_default_height)); + this->setSizeHint(COL_2_PROGRESS_BAR, QSize(COLUMN_DEFAULT_WIDTH, ROW_DEFAULT_HEIGHT)); this->setFlags(Qt::ItemIsEditable | flags()); connect(m_downloadItem, SIGNAL(changed()), this, SLOT(updateItem())); @@ -401,14 +379,14 @@ void QueueItem::updateItem() QString speed = Format::currentSpeedToString(m_downloadItem->speed()); - this->setText(col_0_file_name , m_downloadItem->localFileName()); - this->setText(col_1_website_domain , m_downloadItem->sourceUrl().host()); /// \todo domain only - this->setData(col_2_progress_bar , StateRole, m_downloadItem->state()); - this->setData(col_2_progress_bar , ProgressRole, m_downloadItem->progress()); - this->setText(col_3_percent , QString("%0%").arg(qMax(0, m_downloadItem->progress()))); - this->setText(col_4_size , size); - this->setText(col_5_estimated_time , estimatedTime(m_downloadItem)); - this->setText(col_6_speed , speed); + this->setText(COL_0_FILE_NAME , m_downloadItem->localFileName()); + this->setText(COL_1_WEBSITE_DOMAIN , m_downloadItem->sourceUrl().host()); /// \todo domain only + this->setData(COL_2_PROGRESS_BAR , StateRole, m_downloadItem->state()); + this->setData(COL_2_PROGRESS_BAR , ProgressRole, m_downloadItem->progress()); + this->setText(COL_3_PERCENT , QString("%0%").arg(qMax(0, m_downloadItem->progress()))); + this->setText(COL_4_SIZE , size); + this->setText(COL_5_ESTIMATED_TIME , estimatedTime(m_downloadItem)); + this->setText(COL_6_SPEED , speed); //item->setText(C_COL_7_SEGMENTS, "Unknown"); // todo etc... @@ -417,13 +395,11 @@ void QueueItem::updateItem() /****************************************************************************** ******************************************************************************/ DownloadQueueView::DownloadQueueView(QWidget *parent) : QWidget(parent) - , m_downloadEngine(Q_NULLPTR) , m_queueView(new QueueView(this)) - , m_contextMenu(Q_NULLPTR) { this->setContextMenuPolicy(Qt::CustomContextMenu); - connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenu(const QPoint &))); + + connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); // Main queue list m_queueView->setItemDelegate(new QueueViewItemDelegate(this)); @@ -438,19 +414,15 @@ DownloadQueueView::DownloadQueueView(QWidget *parent) : QWidget(parent) // Edit with second click m_queueView->setEditTriggers(QAbstractItemView::SelectedClicked); - connect(m_queueView, SIGNAL(itemSelectionChanged()), - this, SLOT(onQueueViewItemSelectionChanged())); - connect(m_queueView, SIGNAL(doubleClicked(QModelIndex)), - this, SLOT(onQueueViewDoubleClicked(QModelIndex))); + connect(m_queueView, SIGNAL(itemSelectionChanged()), this, SLOT(onQueueViewItemSelectionChanged())); + connect(m_queueView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(onQueueViewDoubleClicked(QModelIndex))); - connect(m_queueView->itemDelegate(), SIGNAL(commitData(QWidget*)), - this, SLOT(onQueueItemCommitData(QWidget*))); + connect(m_queueView->itemDelegate(), SIGNAL(commitData(QWidget*)), this, SLOT(onQueueItemCommitData(QWidget*))); // Drag-n-Drop - connect(m_queueView, SIGNAL(dropped(QueueItem*)), - this, SLOT(onQueueItemDropped(QueueItem*))); + connect(m_queueView, SIGNAL(dropped(QueueItem*)), this, SLOT(onQueueItemDropped(QueueItem*))); - QLayout* layout = new QGridLayout(this); + auto layout = new QGridLayout(this); layout->addWidget(m_queueView); layout->setContentsMargins(0, 0, 0, 0); @@ -463,15 +435,16 @@ DownloadQueueView::DownloadQueueView(QWidget *parent) : QWidget(parent) ******************************************************************************/ QSize DownloadQueueView::sizeHint() const { - const QHeaderView *header = m_queueView->header(); + auto header = m_queueView->header(); // Add up the sizes of all header sections. The last section is // stretched, so its size is relative to the size of the width; // instead of counting it, we count the size of its largest value. int width = 200; // int width = fontMetrics().horizontalAdvance(tr("Downloading") + " "); - for (int i = 0; i < header->count() - 1; ++i) + for (auto i = 0; i < header->count() - 1; ++i) { width += header->sectionSize(i); + } return QSize(width, QWidget::sizeHint().height()); } @@ -482,7 +455,7 @@ QByteArray DownloadQueueView::saveState(int version) const { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); - stream << version_marker; + stream << VERSION_MARKER; stream << version; stream << columnWidths(); return data; @@ -499,7 +472,7 @@ bool DownloadQueueView::restoreState(const QByteArray &state, int version) int v; stream >> marker; stream >> v; - if (stream.status() != QDataStream::Ok || marker != version_marker || v != version) { + if (stream.status() != QDataStream::Ok || marker != VERSION_MARKER || v != version) { return false; } QList widths; @@ -523,7 +496,7 @@ QList DownloadQueueView::columnWidths() const static int defaultColumnWidth(int index) { - return index == 0 ? column_0_default_width : column_default_width; + return index == 0 ? COLUMN_0_DEFAULT_WIDTH : COLUMN_DEFAULT_WIDTH; } void DownloadQueueView::setColumnWidths(const QList &widths) @@ -544,8 +517,8 @@ void DownloadQueueView::rename() { if (!m_queueView->selectedItems().isEmpty()) { auto treeItem = m_queueView->selectedItems().first(); - m_queueView->setCurrentItem(treeItem, col_0_file_name); - m_queueView->editItem(treeItem, col_0_file_name); + m_queueView->setCurrentItem(treeItem, COL_0_FILE_NAME); + m_queueView->editItem(treeItem, COL_0_FILE_NAME); } } @@ -581,13 +554,13 @@ void DownloadQueueView::setEngine(DownloadEngine *downloadEngine) } if (m_downloadEngine) { - for (const Cx *cx = &connections[0]; cx->signal; cx++) { + for (auto cx = &connections[0]; cx->signal; cx++) { QObject::disconnect(m_downloadEngine, cx->signal, this, cx->slot); } } m_downloadEngine = downloadEngine; if (m_downloadEngine) { - for (const Cx *cx = &connections[0]; cx->signal; cx++) { + for (auto cx = &connections[0]; cx->signal; cx++) { QObject::connect(m_downloadEngine, cx->signal, this, cx->slot); } } @@ -621,7 +594,7 @@ void DownloadQueueView::retranslateUi() ; m_queueView->setHeaderLabels(headers); - for (int index = 0, count = m_queueView->topLevelItemCount(); index < count; ++index) { + for (auto index = 0; index < m_queueView->topLevelItemCount(); ++index) { auto treeItem = m_queueView->topLevelItem(index); auto queueItem = dynamic_cast(treeItem); if (queueItem) { @@ -643,7 +616,7 @@ void DownloadQueueView::restylizeUi() ******************************************************************************/ void DownloadQueueView::onJobAdded(const DownloadRange &range) { - foreach (auto item, range) { + for (auto item : range) { auto downloadItem = dynamic_cast(item); auto queueItem = new QueueItem(downloadItem, m_queueView); m_queueView->addTopLevelItem(queueItem); @@ -652,7 +625,7 @@ void DownloadQueueView::onJobAdded(const DownloadRange &range) void DownloadQueueView::onJobRemoved(const DownloadRange &range) { - foreach (auto item, range) { + for (auto item : range) { auto index = getIndex(item); if (index >= 0) { auto treeItem = m_queueView->takeTopLevelItem(index); @@ -667,7 +640,7 @@ void DownloadQueueView::onJobRemoved(const DownloadRange &range) void DownloadQueueView::onJobStateChanged(IDownloadItem *item) { - QueueItem* queueItem = getQueueItem(item); + auto queueItem = getQueueItem(item); if (queueItem) { queueItem->updateItem(); } @@ -681,7 +654,7 @@ void DownloadQueueView::onSelectionChanged() m_downloadEngine->beginSelectionChange(); auto selection = m_downloadEngine->selection(); - for (int index = 0, count = m_queueView->topLevelItemCount(); index < count; ++index) { + for (auto index = 0; index < m_queueView->topLevelItemCount(); ++index) { auto treeItem = m_queueView->topLevelItem(index); auto queueItem = dynamic_cast(treeItem); auto isSelected = selection.contains(queueItem->downloadItem()); @@ -698,14 +671,14 @@ void DownloadQueueView::onSortChanged() auto selection = m_downloadEngine->selection(); auto items = m_downloadEngine->downloadItems(); - for (int i = 0, total = items.size(); i < total; ++i) { + for (auto i = 0; i < items.size(); ++i) { auto downloadItem = items.at(i); auto index = getIndex(downloadItem); if (index != -1) { // Rem: takeTopLevelItem() changes the selection auto treeItem = m_queueView->takeTopLevelItem(index); if (treeItem) { - m_queueView->insertTopLevelItem(i, treeItem); + m_queueView->insertTopLevelItem(static_cast(i), treeItem); } } } @@ -718,7 +691,7 @@ void DownloadQueueView::onSortChanged() ******************************************************************************/ int DownloadQueueView::getIndex(IDownloadItem *downloadItem) const { - for (int index = 0, count = m_queueView->topLevelItemCount(); index < count; ++index) { + for (auto index = 0; index < m_queueView->topLevelItemCount(); ++index) { auto treeItem = m_queueView->topLevelItem(index); if (treeItem->type() == QTreeWidgetItem::UserType) { auto queueItem = dynamic_cast(treeItem); @@ -742,7 +715,7 @@ QueueItem* DownloadQueueView::getQueueItem(IDownloadItem *downloadItem) } } } - return Q_NULLPTR; + return nullptr; } /****************************************************************************** @@ -760,7 +733,7 @@ void DownloadQueueView::onQueueViewDoubleClicked(const QModelIndex &index) void DownloadQueueView::onQueueViewItemSelectionChanged() { QList selection; - foreach (auto treeItem, m_queueView->selectedItems()) { + for (auto treeItem : m_queueView->selectedItems()) { auto queueItem = dynamic_cast(treeItem); selection << queueItem->downloadItem(); } @@ -774,17 +747,17 @@ void DownloadQueueView::onQueueItemCommitData(QWidget *editor) { auto lineEdit = qobject_cast(editor); if (lineEdit) { - QString newName = lineEdit->text(); + auto newName = lineEdit->text(); // remove extension from base name - int pos = newName.lastIndexOf('.'); + auto pos = newName.lastIndexOf('.'); if (pos != -1) { newName = newName.left(pos); } auto treeItem = m_queueView->currentItem(); auto queueItem = dynamic_cast(treeItem); - AbstractDownloadItem* downloadItem = queueItem->downloadItem(); + auto downloadItem = queueItem->downloadItem(); downloadItem->rename(newName); queueItem->updateItem(); diff --git a/src/widgets/downloadqueueview.h b/src/widgets/downloadqueueview.h index 285ee23d..5bb17179 100644 --- a/src/widgets/downloadqueueview.h +++ b/src/widgets/downloadqueueview.h @@ -33,7 +33,7 @@ class DownloadQueueView : public QWidget Q_OBJECT public: explicit DownloadQueueView(QWidget *parent); - ~DownloadQueueView() Q_DECL_OVERRIDE = default; + ~DownloadQueueView() override = default; DownloadEngine* engine() const; void setEngine(DownloadEngine *downloadEngine); @@ -54,7 +54,7 @@ public slots: void selectionChanged(); protected slots: - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void changeEvent(QEvent *event) override; private slots: void onJobAdded(const DownloadRange &range); @@ -71,9 +71,9 @@ private slots: void showContextMenu(const QPoint &pos) ; private: - DownloadEngine *m_downloadEngine; - QueueView *m_queueView; - QMenu *m_contextMenu; + DownloadEngine *m_downloadEngine = nullptr; + QueueView *m_queueView = nullptr; + QMenu *m_contextMenu = nullptr; void retranslateUi(); void restylizeUi(); diff --git a/src/widgets/downloadqueueview_p.h b/src/widgets/downloadqueueview_p.h index ab04d46f..b3c7103a 100644 --- a/src/widgets/downloadqueueview_p.h +++ b/src/widgets/downloadqueueview_p.h @@ -61,8 +61,8 @@ class QueueView : public QTreeWidget void dropped(QueueItem *queueItem); protected: - void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE; - void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE; + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; private: QPoint dragStartPosition; diff --git a/src/widgets/filtertip.h b/src/widgets/filtertip.h index 539fc7b6..a3c71d2b 100644 --- a/src/widgets/filtertip.h +++ b/src/widgets/filtertip.h @@ -30,7 +30,7 @@ class FilterTip : public QFrame public: explicit FilterTip(QWidget *parent); - ~FilterTip() Q_DECL_OVERRIDE; + ~FilterTip() override; void add(const QString &text, const QString &link); diff --git a/src/widgets/filterwidget.cpp b/src/widgets/filterwidget.cpp index f4b9579f..6e1247ac 100644 --- a/src/widgets/filterwidget.cpp +++ b/src/widgets/filterwidget.cpp @@ -29,9 +29,9 @@ static uint encode(const QList &checkboxes) { - uint code = 0; - for (int i = 0; i < checkboxes.count(); ++i) { - const QCheckBox *checkBox = checkboxes.at(i); + auto code = 0; + for (auto i = 0; i < checkboxes.count(); ++i) { + auto checkBox = checkboxes.at(i); if (checkBox->isChecked()) { code |= (1 << i); } @@ -41,8 +41,8 @@ static uint encode(const QList &checkboxes) static void decode(const uint code, const QList &checkboxes) { - for (int i = 0; i < checkboxes.count(); ++i) { - QCheckBox *checkBox = checkboxes.at(i); + for (auto i = 0; i < checkboxes.count(); ++i) { + auto checkBox = checkboxes.at(i); checkBox->setChecked(code & (1 << i)); } } @@ -62,12 +62,9 @@ FilterWidget::FilterWidget(QWidget *parent) : QWidget(parent) clearFilters(); - connect(ui->fastFilteringOnlyCheckBox, SIGNAL(stateChanged(int)), - this, SLOT(onFilterChanged(int))); - connect(ui->fastFilteringComboBox, SIGNAL(currentTextChanged(QString)), - this, SLOT(onFilterChanged(QString))); - connect(ui->fastFilteringTipToolButton, SIGNAL(released()), - this, SLOT(onFilterTipToolReleased())); + connect(ui->fastFilteringOnlyCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onFilterChanged(int))); + connect(ui->fastFilteringComboBox, SIGNAL(currentTextChanged(QString)), this, SLOT(onFilterChanged(QString))); + connect(ui->fastFilteringTipToolButton, SIGNAL(released()), this, SLOT(onFilterTipToolReleased())); } FilterWidget::~FilterWidget() @@ -102,7 +99,7 @@ void FilterWidget::setState(uint code) inline QList FilterWidget::allCheckBoxes() const { - QList checkboxes = ui->checkBoxGroup->findChildren(); + auto checkboxes = ui->checkBoxGroup->findChildren(); checkboxes.prepend(ui->fastFilteringOnlyCheckBox); return checkboxes; } @@ -135,13 +132,15 @@ void FilterWidget::setFilterHistory(const QStringList &filters) /****************************************************************************** ******************************************************************************/ -void FilterWidget::onFilterChanged(int) +void FilterWidget::onFilterChanged(int state) { + Q_UNUSED(state) emit regexChanged(regex()); } -void FilterWidget::onFilterChanged(const QString &) +void FilterWidget::onFilterChanged(const QString &text) { + Q_UNUSED(text) emit regexChanged(regex()); } @@ -151,8 +150,7 @@ void FilterWidget::onFilterTipToolReleased() { auto tip = new FilterTip(this); - connect(tip, SIGNAL(linkActivated(QString)), - this, SLOT(onFilterTipToolLinkActivated(QString))); + connect(tip, SIGNAL(linkActivated(QString)), this, SLOT(onFilterTipToolLinkActivated(QString))); AutoCloseDialog dialog(tip, ui->fastFilteringTipToolButton); dialog.exec(); @@ -167,21 +165,21 @@ void FilterWidget::onFilterTipToolLinkActivated(const QString& link) ******************************************************************************/ void FilterWidget::clearFilters() { - const QList checkboxes = ui->checkBoxGroup->findChildren(); - foreach (auto checkbox, checkboxes) { + auto checkboxes = ui->checkBoxGroup->findChildren(); + for (auto checkbox : checkboxes) { ui->checkBoxGroup->layout()->removeWidget(checkbox); - checkbox->setParent(Q_NULLPTR); + checkbox->setParent(nullptr); delete checkbox; } } void FilterWidget::addFilter(const QString &name, const QString ®exp) { - const QList checkboxes = ui->checkBoxGroup->findChildren(); - const int count = checkboxes.count(); - const std::div_t dv = std::div(count, 3); - const int row = dv.quot; - const int column = dv.rem; + auto checkboxes = ui->checkBoxGroup->findChildren(); + auto count = static_cast(checkboxes.count()); + auto division = std::div(count, 3); + auto row = division.quot; + auto column = division.rem; auto checkbox = new QCheckBox(name, ui->checkBoxGroup); checkbox->setToolTip(QString("%0\n%1").arg(name, regexp)); @@ -199,15 +197,15 @@ QRegularExpression FilterWidget::regex() const { QString filter; - const QString text = ui->fastFilteringComboBox->currentText(); + auto text = ui->fastFilteringComboBox->currentText(); if (!text.isEmpty()) { filter += "(" + text + ")"; } if (!ui->fastFilteringOnlyCheckBox->isChecked()) { QStringList parts; - const QList checkboxes = ui->checkBoxGroup->findChildren(); - foreach (auto checkbox, checkboxes) { + auto checkboxes = ui->checkBoxGroup->findChildren(); + for (auto checkbox : checkboxes) { if (checkbox->isChecked()) { parts << checkbox->property("regexp").toString(); } @@ -216,7 +214,7 @@ QRegularExpression FilterWidget::regex() const if (!filter.isEmpty()) { filter += "|"; } - foreach (auto part, parts) { + for (auto part : parts) { filter += "("; filter += part; filter += ")|"; diff --git a/src/widgets/filterwidget.h b/src/widgets/filterwidget.h index c252de56..bfe66291 100644 --- a/src/widgets/filterwidget.h +++ b/src/widgets/filterwidget.h @@ -31,7 +31,7 @@ class FilterWidget : public QWidget Q_OBJECT public: explicit FilterWidget(QWidget *parent); - ~FilterWidget() Q_DECL_OVERRIDE; + ~FilterWidget() override; void clearFilters(); void addFilter(const QString &name, const QString ®exp); @@ -51,8 +51,8 @@ class FilterWidget : public QWidget void regexChanged(const QRegularExpression ®ex); private slots: - void onFilterChanged(int); - void onFilterChanged(const QString &); + void onFilterChanged(int state); + void onFilterChanged(const QString &text); void onFilterTipToolReleased(); void onFilterTipToolLinkActivated(const QString& link); diff --git a/src/widgets/linkwidget.cpp b/src/widgets/linkwidget.cpp index c1b1713f..b9dcba55 100644 --- a/src/widgets/linkwidget.cpp +++ b/src/widgets/linkwidget.cpp @@ -17,6 +17,7 @@ #include "linkwidget.h" #include "ui_linkwidget.h" +#include #include #include #include @@ -35,7 +36,6 @@ #include #include -constexpr int elide_char_count = 30; /****************************************************************************** @@ -56,10 +56,10 @@ class LinkWidgetItemDelegate : public CheckableItemDelegate Q_OBJECT public: - explicit LinkWidgetItemDelegate(QObject *parent = Q_NULLPTR); + explicit LinkWidgetItemDelegate(QObject *parent = nullptr); void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + const QModelIndex &index) const override; }; LinkWidgetItemDelegate::LinkWidgetItemDelegate(QObject *parent) @@ -75,8 +75,8 @@ void LinkWidgetItemDelegate::paint(QPainter *painter, initStyleOption(&myOption, index); if (index.column() == 1) { - const QUrl url(myOption.text); - const QPixmap pixmap = MimeDatabase::fileIcon(url, thumbnailHint()); + auto url = QUrl(myOption.text); + auto pixmap = MimeDatabase::fileIcon(url, thumbnailHint()); myOption.icon.addPixmap(pixmap); myOption.decorationAlignment = Qt::AlignHCenter |Qt::AlignVCenter; myOption.decorationPosition = QStyleOptionViewItem::Left; @@ -89,7 +89,6 @@ void LinkWidgetItemDelegate::paint(QPainter *painter, ******************************************************************************/ LinkWidget::LinkWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::LinkWidget) - , m_model(Q_NULLPTR) { ui->setupUi(this); @@ -161,7 +160,7 @@ void LinkWidget::onSectionResized(int logicalIndex, int /*oldSize*/, int newSize void LinkWidget::resizeSection(CheckableTableView *view, int logicalIndex, int newSize) { - QHeaderView *header = view->horizontalHeader(); + auto header = view->horizontalHeader(); QSignalBlocker blocker(header); header->resizeSection(logicalIndex, newSize); } @@ -179,8 +178,8 @@ void LinkWidget::setModel(Model *model) disconnect(m_model->linkModel(), SIGNAL(resourceChanged()), this, SLOT(onResourceChanged())); disconnect(m_model->contentModel(), SIGNAL(resourceChanged()), this, SLOT(onResourceChanged())); - ui->linkTableView->setModel(Q_NULLPTR); - ui->contentTableView->setModel(Q_NULLPTR); + ui->linkTableView->setModel(nullptr); + ui->contentTableView->setModel(nullptr); } m_model = model; if (m_model) { @@ -234,15 +233,15 @@ void LinkWidget::contextMenuCallback(QMenu *contextMenu) if (!contextMenu) { return; } - QAction *actionMask = new QAction(tr("Mask..."), contextMenu); + auto actionMask = new QAction(tr("Mask..."), contextMenu); actionMask->setIcon(QIcon::fromTheme("mask")); connect(actionMask, SIGNAL(triggered()), this, SLOT(customizeMask())); - QAction *actionCopyLinks = new QAction(tr("Copy Links"), contextMenu); + auto actionCopyLinks = new QAction(tr("Copy Links"), contextMenu); actionCopyLinks->setShortcut(QKeySequence::Copy); connect(actionCopyLinks, SIGNAL(triggered()), this, SLOT(copyLinks())); - QAction *actionOpen = new QAction(textForOpenAction(), contextMenu); + auto actionOpen = new QAction(textForOpenAction(), contextMenu); actionOpen->setIcon(QIcon::fromTheme("file-open")); actionOpen->setShortcut(QKeySequence::Open); connect(actionOpen, SIGNAL(triggered()), this, SLOT(open())); @@ -263,20 +262,19 @@ void LinkWidget::customizeMask() void LinkWidget::copyLinks() { QString input; - foreach (auto index, currentTableView()->selectedIndexesAtColumn(1)) { - const QString text = index.model()->data(index, Qt::DisplayRole).toString(); + for (auto index : currentTableView()->selectedIndexesAtColumn(1)) { + auto text = index.model()->data(index, Qt::DisplayRole).toString(); input.append(text); input.append('\n'); } - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(input); + QApplication::clipboard()->setText(input); } void LinkWidget::open() { - foreach (auto index, currentTableView()->selectedIndexesAtColumn(1)) { - const QString text = index.model()->data(index, Qt::DisplayRole).toString(); - QUrl url(text); + for (auto index : currentTableView()->selectedIndexesAtColumn(1)) { + auto text = index.model()->data(index, Qt::DisplayRole).toString(); + auto url = QUrl(text); QDesktopServices::openUrl(url); } } @@ -285,17 +283,17 @@ void LinkWidget::open() ******************************************************************************/ static inline QString elide(const QString &text) { - if (text.length() > 2 * elide_char_count) { - return QString("%0...%1").arg(text.left(elide_char_count), text.right(elide_char_count)); + if (text.length() > 2 * ELIDE_CHAR_COUNT) { + return QString("%0...%1").arg(text.left(ELIDE_CHAR_COUNT), text.right(ELIDE_CHAR_COUNT)); } return text; } inline QString LinkWidget::textForOpenAction() const { - const QModelIndexList indexes = currentTableView()->selectionModel()->selectedIndexes(); + auto indexes = currentTableView()->selectionModel()->selectedIndexes(); QModelIndexList urlIndexes; - foreach (auto index, indexes) { + for (auto index : indexes) { if (index.column() == 1) { urlIndexes.append(index); } @@ -304,8 +302,8 @@ inline QString LinkWidget::textForOpenAction() const return QLatin1String("-"); } if (urlIndexes.count() == 1) { - const QModelIndex urlIndex = urlIndexes.first(); - const QString text = urlIndex.model()->data(urlIndex, Qt::DisplayRole).toString(); + auto urlIndex = urlIndexes.first(); + auto text = urlIndex.model()->data(urlIndex, Qt::DisplayRole).toString(); return tr("Open %0").arg(elide(text)); } return tr("Open %0 Links").arg(urlIndexes.count()); diff --git a/src/widgets/linkwidget.h b/src/widgets/linkwidget.h index 6eb9c381..2e824734 100644 --- a/src/widgets/linkwidget.h +++ b/src/widgets/linkwidget.h @@ -33,7 +33,7 @@ class LinkWidget : public QWidget Q_OBJECT public: explicit LinkWidget(QWidget *parent); - ~LinkWidget() Q_DECL_OVERRIDE; + ~LinkWidget() override; Model* model() const; void setModel(Model *model); @@ -44,7 +44,7 @@ class LinkWidget : public QWidget void contextMenuCallback(QMenu *contextMenu); protected: - void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *event) override; private slots: void onCurrentTabChanged(int index); @@ -56,8 +56,8 @@ private slots: void open(); private: - Ui::LinkWidget *ui; - Model *m_model; + Ui::LinkWidget *ui = nullptr; + Model *m_model = nullptr; void setup(CheckableTableView *view); void resizeSection(CheckableTableView *view, int logicalIndex, int newSize); diff --git a/src/widgets/masktip.cpp b/src/widgets/masktip.cpp index 50e9fa2e..99a728f1 100644 --- a/src/widgets/masktip.cpp +++ b/src/widgets/masktip.cpp @@ -31,7 +31,7 @@ MaskTip::MaskTip(QWidget *parent) : QFrame(parent) ui->groupBox->setLayout(new QVBoxLayout()); - foreach (auto tag, Mask::tags()) { + for (auto tag : Mask::tags()) { add(Mask::description(tag), tag); } } diff --git a/src/widgets/masktip.h b/src/widgets/masktip.h index 1d563b41..df78b292 100644 --- a/src/widgets/masktip.h +++ b/src/widgets/masktip.h @@ -30,7 +30,7 @@ class MaskTip : public QFrame public: explicit MaskTip(QWidget *parent); - ~MaskTip() Q_DECL_OVERRIDE; + ~MaskTip() override; void add(const QString &text, const QString &link); diff --git a/src/widgets/maskwidget.h b/src/widgets/maskwidget.h index 5147df22..5ee33c0f 100644 --- a/src/widgets/maskwidget.h +++ b/src/widgets/maskwidget.h @@ -28,7 +28,7 @@ class MaskWidget : public QWidget Q_OBJECT public: explicit MaskWidget(QWidget *parent); - ~MaskWidget() Q_DECL_OVERRIDE; + ~MaskWidget() override; QString currentMask() const; void setCurrentMask(const QString &text); diff --git a/src/widgets/pathwidget.h b/src/widgets/pathwidget.h index d3e5ad36..579e4126 100644 --- a/src/widgets/pathwidget.h +++ b/src/widgets/pathwidget.h @@ -30,8 +30,8 @@ class PathWidget : public QWidget public: enum PathType { File, Directory }; - explicit PathWidget(QWidget *parent = Q_NULLPTR); - ~PathWidget() Q_DECL_OVERRIDE; + explicit PathWidget(QWidget *parent = nullptr); + ~PathWidget() override; QString currentPath() const; void setCurrentPath(const QString &path); diff --git a/src/widgets/streamformatpicker.cpp b/src/widgets/streamformatpicker.cpp index 23fc09e7..4969b117 100644 --- a/src/widgets/streamformatpicker.cpp +++ b/src/widgets/streamformatpicker.cpp @@ -98,8 +98,7 @@ StreamFormatPicker::StreamFormatPicker(QWidget *parent) : QWidget(parent) connect(ui->buttonVideo, SIGNAL(released()), this, SLOT(onButtonBarClicked())); connect(ui->buttonOther, SIGNAL(released()), this, SLOT(onButtonBarClicked())); - connect(ui->listView->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), - this, SLOT(onCurrentChanged(QModelIndex, QModelIndex))); + connect(ui->listView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(onCurrentChanged(QModelIndex,QModelIndex))); connect(ui->audioComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); connect(ui->videoComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onCurrentIndexChanged(int))); @@ -142,7 +141,7 @@ void StreamFormatPicker::select(const StreamFormatId &formatId) { if (!formatId.isEmpty()) { const QSignalBlocker blocker(this); - foreach (auto compoundId, formatId.compoundIds()) { + for (auto compoundId : formatId.compoundIds()) { setCurrentSimple(compoundId); setCurrentAudio(compoundId); setCurrentVideo(compoundId); @@ -207,13 +206,13 @@ void StreamFormatPicker::onButtonBarClicked() ******************************************************************************/ void StreamFormatPicker::propagateIcons() { - const QMap map = { + const QHash hash = { {ui->buttonSimple, "add-stream"}, {ui->buttonAudio, "stream-audio"}, {ui->buttonVideo, "stream-video"}, {ui->buttonOther, "stream-subtitle"} }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } /****************************************************************************** @@ -286,7 +285,7 @@ void StreamFormatPicker::updateButtonBar() void StreamFormatPicker::populateSimple(const QList &formats) { bool checked = true; - foreach (auto format, formats) { + for (auto format : formats) { auto item = new QStandardItem(format.toString()); item->setData(checked, StreamFormatPicker::CheckStateRole); @@ -306,7 +305,7 @@ void StreamFormatPicker::populateSimple(const QList &formats) void StreamFormatPicker::populateComboBox(const QList &formats, QComboBox *comboBox) { comboBox->clear(); - foreach (auto format, formats) { + for (auto format : formats) { QVariant variant; variant.setValue(format.formatId); comboBox->addItem(format.toString(), variant); @@ -382,7 +381,7 @@ StreamFormatId StreamFormatPicker::currentSimple() const return index.data(StreamFormatPicker::FormatIdRole).value(); } } - return StreamFormatId(); + return {}; } StreamFormatId StreamFormatPicker::currentAudio() const diff --git a/src/widgets/streamformatpicker.h b/src/widgets/streamformatpicker.h index aab10993..9a088c81 100644 --- a/src/widgets/streamformatpicker.h +++ b/src/widgets/streamformatpicker.h @@ -40,7 +40,7 @@ class StreamFormatPicker : public QWidget }; explicit StreamFormatPicker(QWidget *parent); - ~StreamFormatPicker() Q_DECL_OVERRIDE; + ~StreamFormatPicker() override; void clear(); void setData(const StreamObject &streamObject); @@ -86,16 +86,13 @@ class RadioItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit RadioItemDelegate(QObject *parent = Q_NULLPTR); + explicit RadioItemDelegate(QObject *parent = nullptr); // painting - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; // editing - bool editorEvent(QEvent *event, QAbstractItemModel *model, - const QStyleOptionViewItem &option, - const QModelIndex &index) Q_DECL_OVERRIDE; + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override; }; #endif // WIDGETS_STREAM_FORMAT_PICKER_H diff --git a/src/widgets/streamlistwidget.cpp b/src/widgets/streamlistwidget.cpp index dc8e6fe7..70a57d0f 100644 --- a/src/widgets/streamlistwidget.cpp +++ b/src/widgets/streamlistwidget.cpp @@ -17,6 +17,7 @@ #include "streamlistwidget.h" #include "ui_streamlistwidget.h" +#include #include #include #include @@ -27,9 +28,6 @@ #include /* std::sort */ -constexpr int column_id_width = 10; -constexpr int column_name_width = 200; - /****************************************************************************** ******************************************************************************/ @@ -49,19 +47,19 @@ class StreamListItemDelegate : public CheckableItemDelegate Q_OBJECT public: - explicit StreamListItemDelegate(QObject *parent = Q_NULLPTR) + explicit StreamListItemDelegate(QObject *parent = nullptr) : CheckableItemDelegate(parent) {} - ~StreamListItemDelegate() Q_DECL_OVERRIDE = default; + ~StreamListItemDelegate() override = default; - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; -void StreamListItemDelegate::paint(QPainter *painter, - const QStyleOptionViewItem &option, - const QModelIndex &index) const +void StreamListItemDelegate::paint( + QPainter *painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const { QStyleOptionViewItem myOption = option; initStyleOption(&myOption, index); @@ -88,23 +86,18 @@ StreamListWidget::StreamListWidget(QWidget *parent) : QWidget(parent) ui->playlistView->setItemDelegate(new StreamListItemDelegate(ui->playlistView)); ui->playlistView->setModel(m_playlistModel); - QList defaultWidths = {-1, column_id_width, column_name_width, -1, -1, -1}; + QList defaultWidths = {-1, COLUMN_ID_WIDTH, COLUMN_NAME_WIDTH, -1, -1, -1}; setColumnWidths(defaultWidths); adjustSize(); - connect(m_playlistModel, SIGNAL(checkStateChanged(QModelIndex, bool)), - this, SLOT(onCheckStateChanged(QModelIndex, bool))); + connect(m_playlistModel, SIGNAL(checkStateChanged(QModelIndex,bool)), this, SLOT(onCheckStateChanged(QModelIndex,bool))); - connect(ui->playlistView->selectionModel(), - SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), - this, SLOT(onSelectionChanged(const QItemSelection &, const QItemSelection &))); + connect(ui->playlistView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(onSelectionChanged(QItemSelection,QItemSelection))); - connect(ui->streamWidget, SIGNAL(streamObjectChanged(StreamObject)), - this, SLOT(onStreamObjectChanged(StreamObject))); + connect(ui->streamWidget, SIGNAL(streamObjectChanged(StreamObject)), this, SLOT(onStreamObjectChanged(StreamObject))); - connect(ui->trackNumberCheckBox, SIGNAL(stateChanged(int)), this, - SLOT(onTrackNumberChecked(int))); + connect(ui->trackNumberCheckBox, SIGNAL(stateChanged(int)), this, SLOT(onTrackNumberChecked(int))); /* Fancy GIF animation */ QMovie *movie = new QMovie(":/resources/animations/spinner.gif"); @@ -302,7 +295,7 @@ QList StreamListWidget::selectedRows() const { QSet rows; auto indexes = ui->playlistView->selectionModel()->selectedRows(0); - foreach (auto index, indexes) { + for (auto index : indexes) { rows.insert(index.row()); } auto list = rows.values(); @@ -341,8 +334,8 @@ void StreamTableModel::setStreamObjects(const QList &streamObjects { clear(); if (!streamObjects.isEmpty()) { - QModelIndex parent = QModelIndex(); // root is always empty - beginInsertRows(parent, 0, streamObjects.count()); + QModelIndex parent = {}; // root is always empty + beginInsertRows(parent, 0, static_cast(streamObjects.count())); m_items = streamObjects; endInsertRows(); } @@ -352,7 +345,7 @@ void StreamTableModel::setStreamObjects(const QList &streamObjects ******************************************************************************/ void StreamTableModel::enableTrackNumberPrefix(bool enable) { - for (int row = 0; row < m_items.count(); ++row) { + for (auto row = 0; row < m_items.count(); ++row) { auto item = m_items.at(row); // copy! auto title = item.title(); auto prefix = QString("%0 ").arg(item.data().playlist_index); @@ -393,7 +386,7 @@ void StreamTableModel::setItemAt(int row, const StreamObject &streamObject) QList StreamTableModel::selection() const { QList selection; - foreach (int row, this->checkedRows()) { + for (auto row : this->checkedRows()) { if (row >= 0 && row < m_items.count()) { selection << m_items.at(row); } @@ -403,7 +396,7 @@ QList StreamTableModel::selection() const int StreamTableModel::columnCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_headers.count(); + return parent.isValid() ? 0 : static_cast(m_headers.count()); } QVariant StreamTableModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -412,23 +405,23 @@ QVariant StreamTableModel::headerData(int section, Qt::Orientation orientation, if (section >= 0 && section < m_headers.count()) { return m_headers.at(section); } - return QVariant(); + return {}; } return QAbstractItemModel::headerData(section, orientation, role); } int StreamTableModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_items.count(); + return parent.isValid() ? 0 : static_cast(m_items.count()); } QVariant StreamTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { - return QVariant(); + return {}; } if (index.row() >= rowCount() || index.row() < 0) { - return QVariant(); + return {}; } if (role == Qt::TextAlignmentRole) { switch (index.column()) { @@ -445,7 +438,7 @@ QVariant StreamTableModel::data(const QModelIndex &index, int role) const } else if (role == Qt::DisplayRole) { auto streamObject = m_items.at(index.row()); switch (index.column()) { - case 0: return QVariant(); + case 0: return {}; case 1: return streamObject.data().playlist_index; case 2: return filenameOrErrorMessage(streamObject); case 3: return streamObject.data().title; diff --git a/src/widgets/streamlistwidget.h b/src/widgets/streamlistwidget.h index b53e4402..b5009f9d 100644 --- a/src/widgets/streamlistwidget.h +++ b/src/widgets/streamlistwidget.h @@ -35,7 +35,7 @@ class StreamListWidget : public QWidget public: explicit StreamListWidget(QWidget *parent); - ~StreamListWidget() Q_DECL_OVERRIDE; + ~StreamListWidget() override; void retranslateUi(); @@ -54,8 +54,8 @@ class StreamListWidget : public QWidget QList selection() const; protected slots: - void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE; - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *event) override; + void changeEvent(QEvent *event) override; private slots: void onSelectionChanged(const QItemSelection &selected, @@ -90,9 +90,9 @@ class StreamTableModel: public CheckableTableModel public: explicit StreamTableModel(QObject *parent); - ~StreamTableModel() Q_DECL_OVERRIDE = default; + ~StreamTableModel() override = default; - void clear() Q_DECL_OVERRIDE; + void clear() override; void retranslateUi(); @@ -104,10 +104,10 @@ class StreamTableModel: public CheckableTableModel QList selection() const; - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; private: QStringList m_headers; diff --git a/src/widgets/streamtoolbox.cpp b/src/widgets/streamtoolbox.cpp index 524f3e3d..2a43ff7f 100644 --- a/src/widgets/streamtoolbox.cpp +++ b/src/widgets/streamtoolbox.cpp @@ -17,13 +17,12 @@ #include "streamtoolbox.h" #include "ui_streamtoolbox.h" +#include #include #include #include -static const QString s_default_caption = QLatin1String("default"); -static const QString s_automatic_caption = QLatin1String("automatic"); StreamToolBox::StreamToolBox(QWidget *parent, Qt::WindowFlags f) : QToolBox(parent, f) @@ -42,7 +41,7 @@ StreamToolBox::StreamToolBox(QWidget *parent, Qt::WindowFlags f) : QToolBox(pare // this event *after* the QToolBox events. // ********************************************************************** auto objs = this->findChildren(); - foreach (auto obj, objs) { + for (auto obj : objs) { if (obj->objectName() == QLatin1String("qt_toolbox_toolboxbutton")) { obj->setCursor(Qt::PointingHandCursor); m_buttons.append(obj); @@ -61,28 +60,28 @@ StreamToolBox::StreamToolBox(QWidget *parent, Qt::WindowFlags f) : QToolBox(pare // ********************************************************************** { QList done; - foreach (auto w, this->findChildren()) { + for (auto w : this->findChildren()) { connect(w, SIGNAL(toggled(bool)), this, SLOT(onChangedBool(bool))); // done << w; } - foreach (auto w, this->findChildren()) { + for (auto w : this->findChildren()) { connect(w, SIGNAL(currentIndexChanged(int)), this, SLOT(onChangedInt(int))); // done << w; } - foreach (auto w, this->findChildren()) { + for (auto w : this->findChildren()) { connect(w, SIGNAL(valueChanged(int)), this, SLOT(onChangedInt(int))); // done << w; } - foreach (auto w, this->findChildren()) { + for (auto w : this->findChildren()) { connect(w, SIGNAL(editingFinished()), this, SLOT(onChanged())); // done << w; } - // foreach (auto w, this->findChildren()) { + // for (auto w : this->findChildren()) { // QSet undone; // if (!done.contains(w)) { // undone.insert(QString::fromLatin1(w->metaObject()->className())); // } - // foreach (auto value, undone.values()) { + // for (auto value : undone.values()) { // qDebug() << Q_FUNC_INFO << "WARNING: unconnected input:" << value; // } // } @@ -108,7 +107,7 @@ void StreamToolBox::initializeSubtitles() { QStringList supportedConvertExts{"srt", "vtt", "ass", "lrc"}; ui->subtitleConvComboBox->clear(); - foreach (auto ext, supportedConvertExts) { + for (auto ext : supportedConvertExts) { ui->subtitleConvComboBox->addItem(ext.toUpper(), ext.toLower()); } ui->subtitleConvComboBox->setCurrentIndex(0); @@ -150,7 +149,7 @@ void StreamToolBox::onSubtitleToggled(bool toggled) void StreamToolBox::setAutoSubtitleHidden(bool hidden) { auto view = qobject_cast(ui->subtitleLangComboBox->view()); - for (int i = 0; i < ui->subtitleLangComboBox->count(); ++i) { + for (auto i = 0; i < ui->subtitleLangComboBox->count(); ++i) { auto origin = ui->subtitleLangComboBox->itemData(i, SubtitleOriginRole); if (isSubtitleAutoGenerated(origin)) { view->setRowHidden(i, hidden); @@ -160,7 +159,7 @@ void StreamToolBox::setAutoSubtitleHidden(bool hidden) bool StreamToolBox::isSubtitleAutoGenerated(const QVariant &origin) const { - return origin.isValid() && origin.toString() == s_automatic_caption; + return origin.isValid() && origin.toString() == CAPTION_AUTOMATIC; } /****************************************************************************** @@ -177,12 +176,12 @@ void StreamToolBox::setData(const StreamObject::Data &data) ui->subtitleLangComboBox->setItemData(1, QLatin1String("all"), SubtitleLangRole); ui->subtitleLangComboBox->insertSeparator(2); auto subtitles = data.subtitleLanguages(); - foreach (auto subtitle, subtitles) { + for (auto subtitle : subtitles) { auto code = subtitle.languageCode.toUpper(); auto label = subtitle.isAutomatic ? QString("%0 (auto-generated) - %1").arg(code, subtitle.languageName) : QString("%0 - %1").arg(code, subtitle.languageName); - auto origin = subtitle.isAutomatic ? s_automatic_caption : s_default_caption; + auto origin = subtitle.isAutomatic ? CAPTION_AUTOMATIC : CAPTION_DEFAULT; ui->subtitleLangComboBox->addItem(label); auto index = ui->subtitleLangComboBox->count() - 1; ui->subtitleLangComboBox->setItemData(index, subtitle.languageCode, SubtitleLangRole); @@ -196,7 +195,7 @@ void StreamToolBox::setData(const StreamObject::Data &data) ui->subtitleExtComboBox->addItem(tr("(default)"), QString()); auto extenstions = data.subtitleExtensions(); extenstions.sort(); - foreach (auto ext, extenstions) { + for (auto ext : extenstions) { ui->subtitleExtComboBox->addItem(ext.toUpper(), ext.toLower()); } ui->subtitleExtComboBox->setCurrentIndex(0); @@ -330,12 +329,12 @@ void StreamToolBox::propagateIcons() #ifdef HACK_CLOSABLE_PAGES void StreamToolBox::_q_onToolButtonReleased() { - QAbstractButton* button = qobject_cast(sender()); + auto button = qobject_cast(sender()); if (button) { if (button == m_buttons.last()) { return; } - auto index = m_buttons.indexOf(button); + auto index = static_cast(m_buttons.indexOf(button)); if (currentIndex() == index) { emit _q_closeToolButton(); } @@ -345,6 +344,6 @@ void StreamToolBox::_q_onToolButtonReleased() void StreamToolBox::_q_onToolButtonClosed() { auto last = m_buttons.count() - 1; - setCurrentIndex(last); + setCurrentIndex(static_cast(last)); } #endif diff --git a/src/widgets/streamtoolbox.h b/src/widgets/streamtoolbox.h index 276d0c9b..ef8a7eae 100644 --- a/src/widgets/streamtoolbox.h +++ b/src/widgets/streamtoolbox.h @@ -39,7 +39,7 @@ class StreamToolBox : public QToolBox }; explicit StreamToolBox(QWidget *parent, Qt::WindowFlags f = Qt::WindowFlags()); - ~StreamToolBox() Q_DECL_OVERRIDE; + ~StreamToolBox() override; void clear(); void setData(const StreamObject::Data &data); diff --git a/src/widgets/streamwidget.cpp b/src/widgets/streamwidget.cpp index 0634b512..b944f6c8 100644 --- a/src/widgets/streamwidget.cpp +++ b/src/widgets/streamwidget.cpp @@ -41,11 +41,7 @@ StreamWidget::StreamWidget(QWidget *parent) : QWidget(parent) ui->stackedWidget->setCurrentWidget(ui->pageInfo); QFontMetrics fm(ui->fileExtensionEdit->font()); -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) int pixelsWide = fm.horizontalAdvance(".webm3"); -#else - int pixelsWide = fm.width(".webm3"); -#endif ui->fileExtensionEdit->setMaximumWidth(pixelsWide); ui->fileExtensionEdit->setMinimumWidth(pixelsWide); } diff --git a/src/widgets/streamwidget.h b/src/widgets/streamwidget.h index b50fb54b..fa5d840a 100644 --- a/src/widgets/streamwidget.h +++ b/src/widgets/streamwidget.h @@ -31,7 +31,7 @@ class StreamWidget : public QWidget Q_OBJECT public: explicit StreamWidget(QWidget *parent); - ~StreamWidget() Q_DECL_OVERRIDE; + ~StreamWidget() override; void setStreamObject(const StreamObject &streamObject); diff --git a/src/widgets/systemtray.cpp b/src/widgets/systemtray.cpp index 2b1150fe..3e5da7ea 100644 --- a/src/widgets/systemtray.cpp +++ b/src/widgets/systemtray.cpp @@ -142,11 +142,7 @@ void SystemTray::showBalloon(const QString &title, const QString &message) { if (m_settings->isSystemTrayBalloonEnabled()) { if (QSystemTrayIcon::supportsMessages()) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) m_trayIcon->showMessage(title, message, QIcon(":/resources/logo/icon48.png")); -#else - m_trayIcon->showMessage(title, message); -#endif } } } diff --git a/src/widgets/systemtray.h b/src/widgets/systemtray.h index 112ebf09..eb905355 100644 --- a/src/widgets/systemtray.h +++ b/src/widgets/systemtray.h @@ -28,8 +28,8 @@ class SystemTray : public QWidget { Q_OBJECT public: - explicit SystemTray(QWidget *parent = Q_NULLPTR); - ~SystemTray() Q_DECL_OVERRIDE = default; + explicit SystemTray(QWidget *parent = nullptr); + ~SystemTray() override = default; QString title() const; void setTitle(const QString &title); @@ -51,8 +51,8 @@ class SystemTray : public QWidget void hideParentWidget(); protected slots: - void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE; - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void closeEvent(QCloseEvent *event) override; + void changeEvent(QEvent *event) override; private slots: void onSystemTrayIconActivated(QSystemTrayIcon::ActivationReason reason); @@ -61,11 +61,11 @@ private slots: void onSettingsChanged(); private: - Settings *m_settings{Q_NULLPTR}; + Settings *m_settings{nullptr}; QSystemTrayIcon *m_trayIcon; - QAction* m_titleAction{Q_NULLPTR}; - QAction* m_restoreAction{Q_NULLPTR}; - QAction* m_hideWhenMinimizedAction{Q_NULLPTR}; + QAction* m_titleAction{nullptr}; + QAction* m_restoreAction{nullptr}; + QAction* m_hideWhenMinimizedAction{nullptr}; void retranslateUi(); }; diff --git a/src/widgets/textedit.cpp b/src/widgets/textedit.cpp index 402b0e44..84e57fa1 100644 --- a/src/widgets/textedit.cpp +++ b/src/widgets/textedit.cpp @@ -81,17 +81,17 @@ void BlockSelector::setPosition(int line, int column, MoveMode anchor) QTextCursor cursor = m_editor->textCursor(); if (anchor == KeepAnchor) { - const QTextBlock blockAnchor = m_editor->document()->findBlockByNumber(anchorLine); + auto blockAnchor = m_editor->document()->findBlockByNumber(anchorLine); cursor.setPosition(blockAnchor.position() + qMin(anchorColumn, blockAnchor.length() - 1 ), QTextCursor::MoveAnchor ); - const QTextBlock blockCursor = m_editor->document()->findBlockByNumber(cursorLine); + auto blockCursor = m_editor->document()->findBlockByNumber(cursorLine); cursor.setPosition(blockCursor.position() + qMin(cursorColumn, blockCursor.length() - 1 ), QTextCursor::KeepAnchor ); } else { // MoveAnchor - const QTextBlock blockCursor = m_editor->document()->findBlockByNumber(cursorLine); + auto blockCursor = m_editor->document()->findBlockByNumber(cursorLine); cursor.setPosition(blockCursor.position() + qMin(cursorColumn, blockCursor.length() - 1 ), QTextCursor::MoveAnchor ); @@ -107,8 +107,7 @@ void BlockSelector::setPosition(int line, int column, MoveMode anchor) ******************************************************************************/ TextEdit::TextEdit(QWidget *parent) : QPlainTextEdit(parent) { - connect(this, SIGNAL(updateRequest(const QRect &, int)), - this, SLOT(onUpdateRequest(const QRect &, int))); + connect(this, SIGNAL(updateRequest(QRect,int)), this, SLOT(onUpdateRequest(QRect,int))); setCursorWidth(2); setBlockModeEnabled(false); @@ -135,7 +134,7 @@ void TextEdit::setBlockModeEnabled(bool enabled) if (isBlockModeEnabled() != enabled) { if (enabled) { if (!m_blockSelector.isActive()) { - const QTextCursor cursor = textCursor(); + auto cursor = textCursor(); m_blockSelector.setPosition(cursor.anchor() ); m_blockSelector.setPosition(cursor.position(), BlockSelector::KeepAnchor); } @@ -393,7 +392,7 @@ void TextEdit::paintBlockSelector(QPaintEvent *e) cursorPosition = m_blockSelector.cursorPosition(blnum); } - foreach (auto range, context.selections) { + for (const auto &range: context.selections) { const int selStart = range.cursor.selectionStart() - blpos; const int selEnd = range.cursor.selectionEnd() - blpos; if (selStart < bllen && selEnd > 0 @@ -471,17 +470,17 @@ void TextEdit::paintBlockSelector(QPaintEvent *e) void TextEdit::mousePressEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { - const QTextCursor cursorLastPosition = textCursor(); - const QTextCursor cursorUnderMouse = cursorForPosition(e->pos()); - if (e->modifiers() == Qt::NoModifier ) { + auto cursorLastPosition = textCursor(); + auto cursorUnderMouse = cursorForPosition(e->pos()); + if (e->modifiers() == Qt::NoModifier) { // Nothing } else if ((e->modifiers() & Qt::AltModifier) && !(e->modifiers() & Qt::ShiftModifier)) { // Mouse Left + Alt without Shift = block start selection - const int line = cursorUnderMouse.blockNumber(); - const int column = qCeil(qreal(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); + auto line = cursorUnderMouse.blockNumber(); + auto column = qCeil(static_cast(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); m_blockSelector.setPosition(line, column); e->accept(); return; @@ -493,13 +492,13 @@ void TextEdit::mousePressEvent(QMouseEvent *e) QTextCursor selection = cursorLastPosition; selection.setPosition( cursorLastPosition.anchor() ); if (!m_blockSelector.isActive()) { - const int line = selection.blockNumber(); - int column = qMin(selection.block().text().size(), selection.positionInBlock()); + auto line = selection.blockNumber(); + auto column = qMin(static_cast(selection.block().text().size()), selection.positionInBlock()); m_blockSelector.setPosition(line, column); } selection.setPosition( cursorUnderMouse.position(), QTextCursor::KeepAnchor ); - const int line = cursorUnderMouse.blockNumber(); - const int column = qCeil(qreal(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); + auto line = cursorUnderMouse.blockNumber(); + auto column = qCeil(static_cast(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); m_blockSelector.setPosition(line, column, BlockSelector::KeepAnchor); return; @@ -521,7 +520,7 @@ void TextEdit::mousePressEvent(QMouseEvent *e) setBlockModeEnabled(false); } } else if (e->button() == Qt::RightButton) { - int eventCursorPosition = cursorForPosition(e->pos()).position(); + auto eventCursorPosition = cursorForPosition(e->pos()).position(); if (eventCursorPosition < textCursor().selectionStart() || eventCursorPosition > textCursor().selectionEnd()) { setTextCursor(cursorForPosition(e->pos())); @@ -543,9 +542,9 @@ void TextEdit::mouseMoveEvent(QMouseEvent *e) setBlockModeEnabled(true); - const QTextCursor cursorUnderMouse = cursorForPosition(e->pos()); - const int line = cursorUnderMouse.blockNumber(); - const int column = qCeil(qreal(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); + auto cursorUnderMouse = cursorForPosition(e->pos()); + auto line = cursorUnderMouse.blockNumber(); + auto column = qCeil(static_cast(e->pos().x()) / QFontMetricsF(font()).horizontalAdvance(QLatin1Char(' '))); m_blockSelector.setPosition(line, column, BlockSelector::KeepAnchor); } else { @@ -571,11 +570,12 @@ void TextEdit::mouseDoubleClickEvent(QMouseEvent *e) ******************************************************************************/ void TextEdit::copyBlockSelection() { - if (m_blockSelector.isEmpty()) + if (m_blockSelector.isEmpty()) { return; + } QString text; - for (int i = m_blockSelector.topLine(); i <= m_blockSelector.bottomLine(); ++i) { + for (auto i = m_blockSelector.topLine(); i <= m_blockSelector.bottomLine(); ++i) { auto block = document()->findBlockByLineNumber(i).text(); block = block.leftJustified(m_blockSelector.leftColumn() + m_blockSelector.width() + 1, ' '); auto fragment = block.mid(m_blockSelector.leftColumn(), m_blockSelector.width()); @@ -589,11 +589,12 @@ void TextEdit::copyBlockSelection() void TextEdit::pasteBlockSelection() { - if (m_blockSelector.isEmpty()) + if (m_blockSelector.isEmpty()) { return; + } - QClipboard *clipboard = QApplication::clipboard(); - const QMimeData *mimeData = clipboard->mimeData(); + auto clipboard = QApplication::clipboard(); + auto mimeData = clipboard->mimeData(); QString fragment; if (mimeData->hasHtml()) { @@ -606,11 +607,12 @@ void TextEdit::pasteBlockSelection() QString TextEdit::fragmentToPaste(const QString &input) { - QStringList list = input.split(QRegularExpression("[\\r\\n]"), Qt::KeepEmptyParts); + static QRegularExpression reLineCarriage("[\\r\\n]"); + auto list = input.split(reLineCarriage, Qt::KeepEmptyParts); if (!list.isEmpty()) { return list.first(); } - return QString(); + return {}; } void TextEdit::removeBlockSelection(const QString &text) @@ -618,20 +620,20 @@ void TextEdit::removeBlockSelection(const QString &text) if (m_blockSelector.isEmpty()) return; - QTextCursor cursor = textCursor(); + auto cursor = textCursor(); cursor.beginEditBlock(); - int topLine = m_blockSelector.topLine(); - int bottomLine = m_blockSelector.bottomLine(); - int leftColumn = m_blockSelector.leftColumn(); - int rightColumn = m_blockSelector.rightColumn(); + auto topLine = m_blockSelector.topLine(); + auto bottomLine = m_blockSelector.bottomLine(); + auto leftColumn = m_blockSelector.leftColumn(); + auto rightColumn = m_blockSelector.rightColumn(); - QTextBlock block = document()->findBlockByNumber( topLine ); - const QTextBlock lastBlock = document()->findBlockByNumber( bottomLine ); + auto block = document()->findBlockByNumber( topLine ); + auto lastBlock = document()->findBlockByNumber( bottomLine ); for (;;) { // for each selected line - int endPos = qMin( rightColumn, block.length()-1 ) ; - if (leftColumn < block.length()-1 ) { + auto endPos = qMin( rightColumn, block.length() - 1 ) ; + if (leftColumn < block.length() - 1 ) { cursor.setPosition( block.position() + leftColumn, QTextCursor::MoveAnchor); cursor.setPosition( block.position() + endPos, QTextCursor::KeepAnchor); cursor.removeSelectedText(); @@ -644,16 +646,17 @@ void TextEdit::removeBlockSelection(const QString &text) if (!text.isEmpty()) { cursor.insertText( text ); } - if (block == lastBlock) + if (block == lastBlock) { break; + } block = block.next(); } if (!text.isEmpty()) { - leftColumn = leftColumn + text.length(); + leftColumn = leftColumn + static_cast(text.length()); } - int anchorLine = m_blockSelector.anchorLine; - int cursorLine = m_blockSelector.cursorLine; + auto anchorLine = m_blockSelector.anchorLine; + auto cursorLine = m_blockSelector.cursorLine; m_blockSelector.setPosition(anchorLine, leftColumn, BlockSelector::MoveAnchor); m_blockSelector.setPosition(cursorLine, leftColumn, BlockSelector::KeepAnchor); @@ -666,35 +669,38 @@ void TextEdit::deleteBlockSelection(bool after) if (m_blockSelector.isEmpty()) return; - QTextCursor cursor = textCursor(); + auto cursor = textCursor(); cursor.beginEditBlock(); - int topLine = m_blockSelector.topLine(); - int bottomLine = m_blockSelector.bottomLine(); - int leftColumn = m_blockSelector.leftColumn(); + auto topLine = m_blockSelector.topLine(); + auto bottomLine = m_blockSelector.bottomLine(); + auto leftColumn = m_blockSelector.leftColumn(); - QTextBlock block = document()->findBlockByNumber( topLine ); - const QTextBlock lastBlock = document()->findBlockByNumber( bottomLine ); + auto block = document()->findBlockByNumber( topLine ); + auto lastBlock = document()->findBlockByNumber( bottomLine ); for (;;) { // for each selected line - if (leftColumn < block.length()-1 ) { + if (leftColumn < block.length() - 1 ) { cursor.setPosition( block.position() + leftColumn, QTextCursor::MoveAnchor); - if(after){ + if (after){ cursor.deleteChar(); - }else{ - if(leftColumn>0) + } else { + if (leftColumn > 0) { cursor.deletePreviousChar(); + } } } - if (block == lastBlock) + if (block == lastBlock) { break; + } block = block.next(); } - if( !after ) + if (!after) { --leftColumn; + } - int anchorLine = m_blockSelector.anchorLine; - int cursorLine = m_blockSelector.cursorLine; + auto anchorLine = m_blockSelector.anchorLine; + auto cursorLine = m_blockSelector.cursorLine; m_blockSelector.setPosition(anchorLine, leftColumn, BlockSelector::MoveAnchor); m_blockSelector.setPosition(cursorLine, leftColumn, BlockSelector::KeepAnchor); @@ -703,11 +709,12 @@ void TextEdit::deleteBlockSelection(bool after) void TextEdit::clearBlockSelection() { - if (m_blockSelector.isEmpty()) + if (m_blockSelector.isEmpty()) { return; + } m_blockSelector.clear(); - QTextCursor cursor = textCursor(); + auto cursor = textCursor(); cursor.clearSelection(); setTextCursor(cursor); } diff --git a/src/widgets/textedit.h b/src/widgets/textedit.h index d318ccf5..cfdf4425 100644 --- a/src/widgets/textedit.h +++ b/src/widgets/textedit.h @@ -66,8 +66,8 @@ class TextEdit : public QPlainTextEdit { Q_OBJECT public: - explicit TextEdit(QWidget *parent = Q_NULLPTR); - ~TextEdit() Q_DECL_OVERRIDE = default; + explicit TextEdit(QWidget *parent = nullptr); + ~TextEdit() override = default; bool isBlockModeEnabled() const; @@ -77,12 +77,12 @@ class TextEdit : public QPlainTextEdit void blockModeEnabled(bool enabled); protected: - void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; - void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE; - void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void mouseMoveEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void mouseReleaseEvent(QMouseEvent *e) Q_DECL_OVERRIDE; - void mouseDoubleClickEvent(QMouseEvent *e) Q_DECL_OVERRIDE; + void keyPressEvent(QKeyEvent *e) override; + void paintEvent(QPaintEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseDoubleClickEvent(QMouseEvent *e) override; public slots: void setBlockModeEnabled(bool enabled); diff --git a/src/widgets/texteditorwidget.cpp b/src/widgets/texteditorwidget.cpp index e4d867d7..01079d9b 100644 --- a/src/widgets/texteditorwidget.cpp +++ b/src/widgets/texteditorwidget.cpp @@ -83,7 +83,7 @@ QString TextEditorWidget::at(int lineNumber) const QTextBlock textBlock = ui->textEdit->document()->findBlockByLineNumber(lineNumber); return textBlock.text().simplified(); } - return QString(); + return {}; } /****************************************************************************** @@ -110,7 +110,7 @@ void TextEditorWidget::onBlockModeToggled(bool checked) ******************************************************************************/ void TextEditorWidget::propagateIcons() { - const QMap map = { + const QHash hash = { {ui->editblockmode, "edit-block-mode"}, {ui->editcopy , "edit-copy"}, {ui->editcut , "edit-cut"}, @@ -118,5 +118,5 @@ void TextEditorWidget::propagateIcons() {ui->editredo , "edit-redo"}, {ui->editundo , "edit-undo"} }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } diff --git a/src/widgets/texteditorwidget.h b/src/widgets/texteditorwidget.h index d188158a..d1366406 100644 --- a/src/widgets/texteditorwidget.h +++ b/src/widgets/texteditorwidget.h @@ -27,8 +27,8 @@ class TextEditorWidget : public QWidget { Q_OBJECT public: - explicit TextEditorWidget(QWidget *parent = Q_NULLPTR); - ~TextEditorWidget() Q_DECL_OVERRIDE; + explicit TextEditorWidget(QWidget *parent = nullptr); + ~TextEditorWidget() override; void clear(); void append(const QString &text); diff --git a/src/widgets/themewidget.cpp b/src/widgets/themewidget.cpp index 54082ab4..a2574e12 100644 --- a/src/widgets/themewidget.cpp +++ b/src/widgets/themewidget.cpp @@ -58,9 +58,9 @@ void ThemeWidget::changeEvent(QEvent *event) */ QMap ThemeWidget::theme() const { - const QString platformStyle = Theme::toPlatformStyle(ui->platformStyleComboBox->currentIndex()); - const QString iconTheme = Theme::toIconTheme(ui->iconThemeComboBox->currentIndex()); - const QString colorScheme = Theme::toColorScheme(ui->colorSchemeComboBox->currentIndex()); + auto platformStyle = Theme::toPlatformStyle(ui->platformStyleComboBox->currentIndex()); + auto iconTheme = Theme::toIconTheme(ui->iconThemeComboBox->currentIndex()); + auto colorScheme = Theme::toColorScheme(ui->colorSchemeComboBox->currentIndex()); QMap map; map.insert(Theme::PlatformStyle, platformStyle); @@ -75,9 +75,9 @@ void ThemeWidget::setTheme(const QMap &map) QSignalBlocker blocker2(ui->iconThemeComboBox); QSignalBlocker blocker3(ui->colorSchemeComboBox); - const QString platformStyle = map.value(Theme::PlatformStyle, QString()).toString(); - const QString iconTheme = map.value(Theme::IconTheme, QString()).toString(); - const QString colorScheme = map.value(Theme::ColorScheme, QString()).toString(); + auto platformStyle = map.value(Theme::PlatformStyle, QString()).toString(); + auto iconTheme = map.value(Theme::IconTheme, QString()).toString(); + auto colorScheme = map.value(Theme::ColorScheme, QString()).toString(); ui->platformStyleComboBox->setCurrentIndex(Theme::fromPlatformStyle(platformStyle)); ui->iconThemeComboBox->setCurrentIndex(Theme::fromIconTheme(iconTheme)); diff --git a/src/widgets/themewidget.h b/src/widgets/themewidget.h index 7aa27cb7..bc588135 100644 --- a/src/widgets/themewidget.h +++ b/src/widgets/themewidget.h @@ -28,8 +28,8 @@ class ThemeWidget : public QWidget Q_OBJECT public: - explicit ThemeWidget(QWidget *parent = Q_NULLPTR); - ~ThemeWidget() Q_DECL_OVERRIDE; + explicit ThemeWidget(QWidget *parent = nullptr); + ~ThemeWidget() override; QMap theme() const; void setTheme(const QMap &map); @@ -38,7 +38,7 @@ class ThemeWidget : public QWidget void changed(); protected: - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void changeEvent(QEvent *event) override; private slots: void comboboxChanged(int value); diff --git a/src/widgets/torrentpiecemap.cpp b/src/widgets/torrentpiecemap.cpp index 39e24c8f..7090e132 100644 --- a/src/widgets/torrentpiecemap.cpp +++ b/src/widgets/torrentpiecemap.cpp @@ -47,8 +47,8 @@ static QColor color(TorrentPieceItem::Status status) static void colorize(QWidget *widget, TorrentPieceItem::Status status) { - QColor _color = color(status); - QPalette pal = widget->palette(); + auto _color = color(status); + auto pal = widget->palette(); pal.setColor(QPalette::Window, _color); widget->setAutoFillBackground(true); widget->setPalette(pal); @@ -69,6 +69,8 @@ static QString decorate(int count, TorrentFileInfo::Priority priority) TorrentPieceMap::TorrentPieceMap(QWidget *parent) : QWidget(parent) , ui(new Ui::TorrentPieceMap) , m_scene(new QGraphicsScene(this)) + , m_workerThread(new TorrentPieceMapWorker(this)) + , m_tileFont(font()) { ui->setupUi(this); @@ -78,22 +80,18 @@ TorrentPieceMap::TorrentPieceMap(QWidget *parent) : QWidget(parent) colorize(ui->boxVerified, TorrentPieceItem::Status::Verified); ui->priorityLabel->setText( - tr("Priority: %0=high %1=normal %2=low %3=ignore").arg( - QString("³"), QString("²"), QString("¹"), QString("°"))); + tr("Priority: %0=high %1=normal %2=low %3=ignore").arg( + QString("³"), QString("²"), QString("¹"), QString("°"))); /* Calculate metrics */ - m_tileFont = font(); + // const int pointSize = m_tileFont.pointSize(); // m_tileFont.setPointSize(pointSize - 1); qRegisterMetaType("TorrentPieceData"); QFontMetrics fm(m_tileFont); -#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) m_tileWidth = fm.horizontalAdvance(decorate(999, TorrentFileInfo::Low)); -#else - m_tileWidth = fm.width(decorate(999, TorrentFileInfo::Low)); -#endif m_tileHeight = fm.height() + 2 * m_tilePadding; m_tileWidth += 2 * m_tilePadding; @@ -116,7 +114,6 @@ TorrentPieceMap::TorrentPieceMap(QWidget *parent) : QWidget(parent) ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground); /* Worker thread */ - m_workerThread = new TorrentPieceMapWorker(this); connect(m_workerThread, &TorrentPieceMapWorker::resultReady, this, &TorrentPieceMap::handleResults); resetUi(); @@ -241,8 +238,8 @@ void TorrentPieceMapWorker::run() #endif m_lock.lockForRead(); - TorrentPieceData pieceData = m_pieceData; - const QList peers = m_peers; + auto pieceData = m_pieceData; + // const QList peers = m_peers; m_lock.unlock(); setDirty(false); @@ -280,7 +277,7 @@ void TorrentPieceMap::updateWidget() pieceData.pieceAvailability = m_torrent->detail().pieceAvailability; pieceData.piecePriority = m_torrent->detail().piecePriority; - const QList peers = m_torrent->detail().peers; + auto peers = m_torrent->detail().peers; m_workerThread->doWork(pieceData, peers); @@ -303,7 +300,7 @@ void TorrentPieceMap::setPieceData(const TorrentPieceData &pieceData) ******************************************************************************/ void TorrentPieceMap::clearScene() { - foreach (auto item, m_items) { + for (auto item : m_items) { m_scene->removeItem(item); } m_items.clear(); @@ -318,20 +315,11 @@ void TorrentPieceMap::populateScene(const TorrentPieceData &pieceData) m_rootItem); auto flags = item->flags(); -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) flags.setFlag(QGraphicsItem::ItemIsMovable, false); flags.setFlag(QGraphicsItem::ItemIsSelectable, false); flags.setFlag(QGraphicsItem::ItemIsFocusable, false); flags.setFlag(QGraphicsItem::ItemSendsGeometryChanges, false); flags.setFlag(QGraphicsItem::ItemSendsScenePositionChanges, false); -#else - flags &= ~QGraphicsItem::ItemIsMovable; - flags &= ~QGraphicsItem::ItemIsMovable; - flags &= ~QGraphicsItem::ItemIsSelectable; - flags &= ~QGraphicsItem::ItemIsFocusable; - flags &= ~QGraphicsItem::ItemSendsGeometryChanges; - flags &= ~QGraphicsItem::ItemSendsScenePositionChanges; -#endif item->setFlags(flags); m_items.append(item); } @@ -344,13 +332,13 @@ void TorrentPieceMap::populateScene(const TorrentPieceData &pieceData) */ void TorrentPieceMap::adjustScene() { - const QSize viewportSize = ui->graphicsView->viewport()->size(); - const int maxWidth = viewportSize.width(); - const qreal width = m_tileWidth + 2 * m_tilePadding; - const qreal height = m_tileHeight + 2 * m_tilePadding; + auto viewportSize = ui->graphicsView->viewport()->size(); + qreal maxWidth = static_cast(viewportSize.width()); + qreal width = m_tileWidth + 2 * m_tilePadding; + qreal height = m_tileHeight + 2 * m_tilePadding; qreal x = 0; qreal y = 0; - foreach (auto item, m_items) { + for (auto item : m_items) { if (x + width >= maxWidth) { x = 0; y += height; @@ -359,7 +347,7 @@ void TorrentPieceMap::adjustScene() x += width; } const QRectF viewportRect(QPointF(0, 0), viewportSize); - const QRectF rect = m_scene->itemsBoundingRect().united(viewportRect); + auto rect = m_scene->itemsBoundingRect().united(viewportRect); m_scene->setSceneRect(rect); } @@ -368,9 +356,9 @@ void TorrentPieceMap::adjustScene() void TorrentPieceMap::updateScene(const TorrentPieceData &pieceData) { Q_ASSERT(pieceData.size == m_items.count()); - const int size = pieceData.size; - for (int i = 0; i < size; ++i) { - TorrentPieceItem *item = m_items.at(i); + auto size = pieceData.size; + for (auto i = 0; i < size; ++i) { + auto item = m_items.at(i); if (i < pieceData.pieceAvailability.size()) { item->setAvailability(pieceData.pieceAvailability.at(i)); @@ -426,7 +414,7 @@ void TorrentPieceMap::retranslateUi() /****************************************************************************** ******************************************************************************/ -TorrentPieceItem::TorrentPieceItem(int width, int height, int padding, +TorrentPieceItem::TorrentPieceItem(qreal width, qreal height, qreal padding, const QFont &font, QGraphicsItem *parent) : QGraphicsItem(parent) , m_font(font) diff --git a/src/widgets/torrentpiecemap.h b/src/widgets/torrentpiecemap.h index 38405bdb..1b195f90 100644 --- a/src/widgets/torrentpiecemap.h +++ b/src/widgets/torrentpiecemap.h @@ -37,12 +37,12 @@ class TorrentPieceItem; struct TorrentPieceData { - int size = 0; - QBitArray availablePieces; - QBitArray downloadedPieces; - QBitArray verifiedPieces; - QVector pieceAvailability; - QVector piecePriority; + qint64 size = 0; + QBitArray availablePieces = {}; + QBitArray downloadedPieces = {}; + QBitArray verifiedPieces = {}; + QVector pieceAvailability = {}; + QVector piecePriority = {}; }; /* Enable the type to be used with QVariant. */ @@ -53,19 +53,19 @@ class TorrentPieceMap : public QWidget { Q_OBJECT public: - explicit TorrentPieceMap(QWidget *parent = Q_NULLPTR); - ~TorrentPieceMap() Q_DECL_OVERRIDE; + explicit TorrentPieceMap(QWidget *parent = nullptr); + ~TorrentPieceMap() override; Torrent *torrent() const; void setTorrent(Torrent *torrent); protected: - void showEvent(QShowEvent *event) Q_DECL_OVERRIDE; - void hideEvent(QHideEvent *event) Q_DECL_OVERRIDE; - void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; + void showEvent(QShowEvent *event) override; + void hideEvent(QHideEvent *event) override; + void resizeEvent(QResizeEvent *event) override; protected slots: - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void changeEvent(QEvent *event) override; private slots: void onChanged(); @@ -73,17 +73,17 @@ private slots: private: Ui::TorrentPieceMap *ui; - Torrent *m_torrent{Q_NULLPTR}; - QGraphicsScene *m_scene; - QGraphicsRectItem *m_rootItem{Q_NULLPTR}; - QList m_items; + Torrent *m_torrent = nullptr; + QGraphicsScene *m_scene = nullptr; + QGraphicsRectItem *m_rootItem = nullptr; + QList m_items = {}; - TorrentPieceMapWorker *m_workerThread; + TorrentPieceMapWorker *m_workerThread = nullptr; - QFont m_tileFont; - int m_tileHeight; - int m_tileWidth; - int m_tilePadding = 1; + QFont m_tileFont = {}; + qreal m_tileHeight = 0; + qreal m_tileWidth = 0; + qreal m_tilePadding = 1; void resetUi(); void retranslateUi(); @@ -103,7 +103,7 @@ class TorrentPieceMapWorker : public QThread { Q_OBJECT public: - TorrentPieceMapWorker(QObject *parent = Q_NULLPTR): QThread(parent) {} + TorrentPieceMapWorker(QObject *parent = nullptr): QThread(parent) {} bool isUseful(); void setUseful(bool useful); @@ -117,15 +117,15 @@ class TorrentPieceMapWorker : public QThread void resultReady(const TorrentPieceData &pieceData); protected: - void run() Q_DECL_OVERRIDE; + void run() override; private: QReadWriteLock m_lock; - bool m_isUseful{false}; - bool m_isDirty{false}; + bool m_isUseful = false; + bool m_isDirty = false; - TorrentPieceData m_pieceData; - QList m_peers; + TorrentPieceData m_pieceData = {}; + QList m_peers = {}; }; /****************************************************************************** @@ -133,32 +133,34 @@ class TorrentPieceMapWorker : public QThread class TorrentPieceItem : public QGraphicsItem { public: - explicit TorrentPieceItem(int width, int height, int padding, - const QFont &font, QGraphicsItem *parent = Q_NULLPTR); - - void setAvailability(int availability); - void setPriority(TorrentFileInfo::Priority priority); - enum class Status { NotAvailable, Available, Downloaded, Verified }; + + explicit TorrentPieceItem( + qreal width, qreal height, qreal padding, + const QFont &font, QGraphicsItem *parent = nullptr); + + void setAvailability(int availability); + void setPriority(TorrentFileInfo::Priority priority); + void setStatus(Status status); - QRectF boundingRect() const Q_DECL_OVERRIDE; - QPainterPath shape() const Q_DECL_OVERRIDE; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) Q_DECL_OVERRIDE; + QRectF boundingRect() const override; + QPainterPath shape() const override; + void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; private: - QFont m_font; - qreal m_width; - qreal m_height; - qreal m_padding; - int m_availability{0}; - TorrentFileInfo::Priority m_priority{TorrentFileInfo::Normal}; - Status m_status{Status::NotAvailable}; + QFont m_font = {}; + qreal m_width = 0; + qreal m_height = 0; + qreal m_padding = 0; + int m_availability = 0; + TorrentFileInfo::Priority m_priority = TorrentFileInfo::Normal; + Status m_status = Status::NotAvailable; }; #endif // WIDGETS_TORRENT_PIECE_MAP_H diff --git a/src/widgets/torrentprogressbar.cpp b/src/widgets/torrentprogressbar.cpp index f0a9b4d0..b9e0d45e 100644 --- a/src/widgets/torrentprogressbar.cpp +++ b/src/widgets/torrentprogressbar.cpp @@ -16,6 +16,7 @@ #include "torrentprogressbar.h" +#include #include #include @@ -25,8 +26,6 @@ #include #include -constexpr int min_progress = 0; -constexpr int max_progress = 100; /*! * \class TorrentProgressBar @@ -36,8 +35,8 @@ constexpr int max_progress = 100; TorrentProgressBar::TorrentProgressBar(QWidget *parent) : QProgressBar(parent) , m_downloadedPieces(QBitArray()) { - setRange(min_progress, max_progress); - setValue(min_progress); + setRange(MIN_PROGRESS, MAX_PROGRESS); + setValue(MIN_PROGRESS); } /****************************************************************************** @@ -68,21 +67,21 @@ void TorrentProgressBar::paintEvent(QPaintEvent *) myOption.palette.setColor(QPalette::All, QPalette::Highlight, s_lightBlue); myOption.palette.setColor(QPalette::All, QPalette::HighlightedText, s_black); - const int progress = value(); + auto progress = value(); CustomStyleOptionProgressBar progressBarOption; progressBarOption.state = myOption.state; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = myOption.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); - progressBarOption.minimum = min_progress; - progressBarOption.maximum = max_progress; + progressBarOption.minimum = MIN_PROGRESS; + progressBarOption.maximum = MAX_PROGRESS; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = false; progressBarOption.palette = myOption.palette; progressBarOption.progress = progress; - progressBarOption.color = progress < max_progress ? s_green : s_darkGreen; - progressBarOption.icon = QIcon(); + progressBarOption.color = progress < MAX_PROGRESS ? s_green : s_darkGreen; + progressBarOption.icon = {}; progressBarOption.hasSegments = true; progressBarOption.segments = m_downloadedPieces; diff --git a/src/widgets/torrentprogressbar.h b/src/widgets/torrentprogressbar.h index 44fbb06d..b2b4ab9b 100644 --- a/src/widgets/torrentprogressbar.h +++ b/src/widgets/torrentprogressbar.h @@ -24,14 +24,14 @@ class TorrentProgressBar : public QProgressBar { Q_OBJECT public: - explicit TorrentProgressBar(QWidget *parent = Q_NULLPTR); - ~TorrentProgressBar() Q_DECL_OVERRIDE = default; + explicit TorrentProgressBar(QWidget *parent = nullptr); + ~TorrentProgressBar() override = default; void clearPieces(); void setPieces(const QBitArray &downloadedPieces); protected: - void paintEvent(QPaintEvent *) Q_DECL_OVERRIDE; + void paintEvent(QPaintEvent *) override; private: QBitArray m_downloadedPieces; diff --git a/src/widgets/torrentwidget.cpp b/src/widgets/torrentwidget.cpp index 292ff6c9..582c71c5 100644 --- a/src/widgets/torrentwidget.cpp +++ b/src/widgets/torrentwidget.cpp @@ -17,6 +17,7 @@ #include "torrentwidget.h" #include "ui_torrentwidget.h" +#include #include #include #include @@ -40,17 +41,14 @@ #include #include -constexpr int column_minimum_width = 10; -constexpr int column_default_width = 100; -constexpr int row_default_height = 18; +using namespace Qt::Literals::StringLiterals; -constexpr int min_progress = 0; -constexpr int max_progress = 100; -constexpr int version_marker = 0xff; +static const int FILE_TABLE_HIDDEN_COLUMN_INDEX = 1; // Hide 'Name' column +static const int FILE_TABLE_PROGRESS_BAR_COLUMN_INDEX = 8; +static const int PEER_TABLE_PROGRESS_BAR_COLUMN_INDEX = 5; + -/****************************************************************************** - ******************************************************************************/ class Headers // Holds column header's widths and titles { public: @@ -58,20 +56,23 @@ class Headers // Holds column header's widths and titles Headers(const QList > &l) {d = l; } Headers &operator=(const QList > &l) { d = l; return *this; } - int count() const { return d.count(); } + qsizetype count() const { return d.count(); } QString title(int index) const { - return (index >= 0 && index < d.count()) ? d.at(index).second : QString(); + return (index >= 0 && index < d.count()) ? d.at(index).second : ""_L1; } - int width(int index) const { - return (index >= 0 && index < d.count()) ? d.at(index).first : column_default_width; + int width(qsizetype index) const + { + return (index >= 0 && index < d.count()) ? d.at(index).first : COLUMN_DEFAULT_WIDTH; } QList widths() const { QList widths; - foreach (auto header, d) { widths << header.first; } + for (const auto &header : d) { + widths << header.first; + } return widths; } @@ -79,54 +80,47 @@ class Headers // Holds column header's widths and titles QList > d; }; -/****************************************************************************** - ******************************************************************************/ -constexpr int file_table_hidden_column_index = 1; // Hide 'Name' column -constexpr int file_table_progress_bar_column_index = 8; - static const Headers fileTableHeaders ({ - { 30, QLatin1String("#")}, - { 320, QLatin1String("Name")}, - { 320, QLatin1String("Path")}, - { 60, QLatin1String("Size")}, - { 60, QLatin1String("Done")}, - { 60, QLatin1String("Percent")}, - { 60, QLatin1String("First Piece")}, - { 60, QLatin1String("# Pieces")}, - { 120, QLatin1String("Pieces")}, // drawn as a progress bar - { 60, QLatin1String("Priority")}, - { 120, QLatin1String("Modification date")}, - { 100, QLatin1String("SHA-1")}, - { 100, QLatin1String("CRC-32")} + { 30, "#"_L1}, + { 320, "Name"_L1}, + { 320, "Path"_L1}, + { 60, "Size"_L1}, + { 60, "Done"_L1}, + { 60, "Percent"_L1}, + { 60, "First Piece"_L1}, + { 60, "# Pieces"_L1}, + { 120, "Pieces"_L1}, // drawn as a progress bar + { 60, "Priority"_L1}, + { 120, "Modification date"_L1}, + { 100, "SHA-1"_L1}, + { 100, "CRC-32"_L1} }); -constexpr int peer_table_progress_bar_column_index = 5; - static const Headers peerTableHeaders ({ - { 120, QLatin1String("IP")}, - { 50, QLatin1String("Port")}, - { 120, QLatin1String("User Agent")}, - { 80, QLatin1String("Downloaded")}, - { 80, QLatin1String("Uploaded")}, - { 120, QLatin1String("Pieces")}, // drawn as a progress bar - { 80, QLatin1String("Request Time")}, - { 80, QLatin1String("Active Time")}, - { 80, QLatin1String("Queue Time")}, - { 160, QLatin1String("Flags")}, - { 100, QLatin1String("Source Flags")} + { 120, "IP"_L1}, + { 50, "Port"_L1}, + { 120, "User Agent"_L1}, + { 80, "Downloaded"_L1}, + { 80, "Uploaded"_L1}, + { 120, "Pieces"_L1}, // drawn as a progress bar + { 80, "Request Time"_L1}, + { 80, "Active Time"_L1}, + { 80, "Queue Time"_L1}, + { 160, "Flags"_L1}, + { 100, "Source Flags"_L1} }); static const Headers trackerTableHeaders ({ - { 360, QLatin1String("Url")}, - { 60, QLatin1String("Id")}, - { 240, QLatin1String("Number of listened sockets (endpoints)")}, - { 160, QLatin1String("Tier this tracker belongs to")}, - { 120, QLatin1String("Max number of failures")}, - { 80, QLatin1String("Source")}, - { 80, QLatin1String("Verified?")} + { 360, "Url"_L1}, + { 60, "Id"_L1}, + { 240, "Number of listened sockets (endpoints)"_L1}, + { 160, "Tier this tracker belongs to"_L1}, + { 120, "Max number of failures"_L1}, + { 80, "Source"_L1}, + { 80, "Verified?"_L1} }); @@ -152,23 +146,23 @@ void FileTableViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewI myOption.font.setBold(true); } - if (index.column() == file_table_progress_bar_column_index) { - const int progress = index.data(AbstractTorrentTableModel::ProgressRole).toInt(); - const QBitArray segments = index.data(AbstractTorrentTableModel::SegmentRole).toBitArray(); + if (index.column() == FILE_TABLE_PROGRESS_BAR_COLUMN_INDEX) { + auto progress = index.data(AbstractTorrentTableModel::ProgressRole).toInt(); + auto segments = index.data(AbstractTorrentTableModel::SegmentRole).toBitArray(); CustomStyleOptionProgressBar progressBarOption; progressBarOption.state = myOption.state; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = myOption.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); - progressBarOption.minimum = min_progress; - progressBarOption.maximum = max_progress; + progressBarOption.minimum = MIN_PROGRESS; + progressBarOption.maximum = MAX_PROGRESS; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = false; progressBarOption.palette = myOption.palette; progressBarOption.progress = progress; progressBarOption.color = progress < 100 ? s_green : s_darkGreen; - progressBarOption.icon = QIcon(); + progressBarOption.icon = {}; progressBarOption.hasSegments = true; progressBarOption.segments = segments; @@ -201,24 +195,24 @@ void PeerTableViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewI myOption.font.setBold(true); } - const bool connected = index.data(AbstractTorrentTableModel::ConnectRole).toBool(); + auto connected = index.data(AbstractTorrentTableModel::ConnectRole).toBool(); if (!connected) { myOption.palette.setColor(QPalette::All, QPalette::Text, s_darkGrey); myOption.palette.setColor(QPalette::All, QPalette::HighlightedText, s_darkGrey); myOption.font.setItalic(true); } - if (index.column() == peer_table_progress_bar_column_index) { - const int progress = index.data(AbstractTorrentTableModel::ProgressRole).toInt(); - const QBitArray segments = index.data(AbstractTorrentTableModel::SegmentRole).toBitArray(); + if (index.column() == PEER_TABLE_PROGRESS_BAR_COLUMN_INDEX) { + auto progress = index.data(AbstractTorrentTableModel::ProgressRole).toInt(); + auto segments = index.data(AbstractTorrentTableModel::SegmentRole).toBitArray(); CustomStyleOptionProgressBar progressBarOption; progressBarOption.state = myOption.state; progressBarOption.direction = QApplication::layoutDirection(); progressBarOption.rect = myOption.rect; progressBarOption.fontMetrics = QApplication::fontMetrics(); - progressBarOption.minimum = min_progress; - progressBarOption.maximum = max_progress; + progressBarOption.minimum = MIN_PROGRESS; + progressBarOption.maximum = MAX_PROGRESS; progressBarOption.textAlignment = Qt::AlignCenter; progressBarOption.textVisible = false; progressBarOption.palette = myOption.palette; @@ -228,7 +222,7 @@ void PeerTableViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewI } else { progressBarOption.color = progress < 100 ? s_grey : s_darkGrey; } - progressBarOption.icon = QIcon(); + progressBarOption.icon = {}; progressBarOption.hasSegments = true; progressBarOption.segments = segments; @@ -268,8 +262,6 @@ void TrackerTableViewItemDelegate::paint(QPainter *painter, const QStyleOptionVi ******************************************************************************/ TorrentWidget::TorrentWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::TorrentWidget) - , m_torrentContext(Q_NULLPTR) - , m_torrent(Q_NULLPTR) { ui->setupUi(this); @@ -312,13 +304,13 @@ void TorrentWidget::setTorrentContext(TorrentBaseContext *torrentContext) ******************************************************************************/ void TorrentWidget::clear() { - m_torrent = Q_NULLPTR; + m_torrent = nullptr; resetUi(); } bool TorrentWidget::isEmpty() const { - return m_torrent == Q_NULLPTR; + return m_torrent == nullptr; } /****************************************************************************** @@ -350,7 +342,7 @@ QByteArray TorrentWidget::saveState(int version) const { QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); - stream << version_marker; + stream << VERSION_MARKER; stream << version; stream << ui->tabWidget->currentIndex(); stream << m_fileColumnsWidths; @@ -364,13 +356,13 @@ bool TorrentWidget::restoreState(const QByteArray &state, int version) if (state.isEmpty()) { return false; } - QByteArray sd = state; + auto sd = state; QDataStream stream(&sd, QIODevice::ReadOnly); int marker; int v; stream >> marker; stream >> v; - if (stream.status() != QDataStream::Ok || marker != version_marker || v != version) { + if (stream.status() != QDataStream::Ok || marker != VERSION_MARKER || v != version) { return false; } int currentTabIndex = 0; @@ -436,15 +428,14 @@ void TorrentWidget::setupUiTableView(QTableView *view) view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel); view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); view->verticalHeader()->setHighlightSections(false); - view->verticalHeader()->setDefaultSectionSize(row_default_height); - view->verticalHeader()->setMinimumSectionSize(row_default_height); + view->verticalHeader()->setDefaultSectionSize(ROW_DEFAULT_HEIGHT); + view->verticalHeader()->setMinimumSectionSize(ROW_DEFAULT_HEIGHT); view->horizontalHeader()->setHighlightSections(false); - view->horizontalHeader()->setDefaultSectionSize(column_default_width); - view->horizontalHeader()->setMinimumSectionSize(column_minimum_width); + view->horizontalHeader()->setDefaultSectionSize(COLUMN_DEFAULT_WIDTH); + view->horizontalHeader()->setMinimumSectionSize(COLUMN_MINIMUM_WIDTH); view->verticalHeader()->setVisible(false); - connect(view->horizontalHeader(), SIGNAL(sectionClicked(int)), - this, SLOT(onSectionClicked(int))); + connect(view->horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(onSectionClicked(int))); } /****************************************************************************** @@ -495,11 +486,15 @@ void TorrentWidget::setupInfoCopy(QLabel *label, QFrame *buddy) buddyTextEdit->setFrameShape(QFrame::NoFrame); } - foreach (auto action, label->actions()) { label->removeAction(action); } - foreach (auto action, buddy->actions()) { buddy->removeAction(action); } + for (auto action : label->actions()) { + label->removeAction(action); + } + for (auto action : buddy->actions()) { + buddy->removeAction(action); + } // Context menu > Copy - QAction *copyAction = new QAction(tr("Copy"), buddy); + auto copyAction = new QAction(tr("Copy"), buddy); connect(copyAction, &QAction::triggered, this, &TorrentWidget::copy); label->setBuddy(buddy); @@ -531,19 +526,16 @@ void TorrentWidget::setupContextMenus() ui->peerTableView->setContextMenuPolicy(Qt::CustomContextMenu); ui->trackerTableView->setContextMenuPolicy(Qt::CustomContextMenu); - connect(ui->fileTableView, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenuFileTable(const QPoint &))); - connect(ui->peerTableView, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenuPeerTable(const QPoint &))); - connect(ui->trackerTableView, SIGNAL(customContextMenuRequested(const QPoint &)), - this, SLOT(showContextMenuTrackerTable(const QPoint &))); - + connect(ui->fileTableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenuFileTable(QPoint))); + connect(ui->peerTableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenuPeerTable(QPoint))); + connect(ui->trackerTableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenuTrackerTable(QPoint))); } /****************************************************************************** ******************************************************************************/ -void TorrentWidget::showContextMenuFileTable(const QPoint &/*pos*/) +void TorrentWidget::showContextMenuFileTable(const QPoint &pos) { + Q_UNUSED(pos) auto contextMenu = new QMenu(this); QAction actionOpen(tr("Open"), contextMenu); @@ -613,7 +605,7 @@ void TorrentWidget::setPriorityByFileOrder() { QSet rows; auto indexes = ui->fileTableView->selectionModel()->selectedRows(); - foreach (auto index, indexes) { + for (auto index : indexes) { rows.insert(index.row()); } if (m_torrentContext) { @@ -623,14 +615,14 @@ void TorrentWidget::setPriorityByFileOrder() void TorrentWidget::setPriority(TorrentFileInfo::Priority priority) { - QItemSelection selection = ui->fileTableView->selectionModel()->selection(); + auto selection = ui->fileTableView->selectionModel()->selection(); auto proxymodel = qobject_cast(ui->fileTableView->model()); if (proxymodel) { selection = proxymodel->mapSelectionToSource(selection); } - QModelIndexList indexes = selection.indexes(); + auto indexes = selection.indexes(); - foreach (auto index, indexes) { + for (auto index : indexes) { if (m_torrentContext) { m_torrentContext->setPriority(m_torrent, index.row(), priority); } @@ -639,8 +631,9 @@ void TorrentWidget::setPriority(TorrentFileInfo::Priority priority) /****************************************************************************** ******************************************************************************/ -void TorrentWidget::showContextMenuPeerTable(const QPoint &/*pos*/) +void TorrentWidget::showContextMenuPeerTable(const QPoint &pos) { + Q_UNUSED(pos) QMenu *contextMenu = new QMenu(this); QAction actionAdd(tr("Add Peer..."), contextMenu); @@ -664,13 +657,15 @@ void TorrentWidget::showContextMenuPeerTable(const QPoint &/*pos*/) void TorrentWidget::addPeer() { bool ok; - QString input = QInputDialog::getText( - this, tr("Add Peer"), - tr("Enter the IP address and port number of the peer to add.\n" - "Ex:\n" - " - for IPv4, type 'x.x.x.x:p'\n" - " - for IPv6, type '[x:x:x:x:x:x:x:x]:p'\n"), - QLineEdit::Normal, QString(), &ok); + auto input = QInputDialog::getText( + this, + tr("Add Peer"), + tr("Enter the IP address and port number of the peer to add.\n" + "Ex:\n" + " - for IPv4, type 'x.x.x.x:p'\n" + " - for IPv6, type '[x:x:x:x:x:x:x:x]:p'\n"), + QLineEdit::Normal, {}, &ok); + if (ok && !input.isEmpty()) { m_torrent->addPeer(input); } @@ -679,16 +674,15 @@ void TorrentWidget::addPeer() void TorrentWidget::copyPeerList() { QStringList addresses; - foreach (auto peer, m_torrent->detail().peers) { + for (auto peer : m_torrent->detail().peers) { addresses.append(peer.endpoint.toString()); } QString text; - foreach (auto address, addresses) { + for (auto address : addresses) { text += address; text += QChar::LineFeed; // '\n' } - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(text); + QApplication::clipboard()->setText(text); } void TorrentWidget::removeUnconnected() @@ -726,10 +720,12 @@ void TorrentWidget::showContextMenuTrackerTable(const QPoint &/*pos*/) void TorrentWidget::addTracker() { bool ok; - QString input = QInputDialog::getText( - this, tr("Add Tracker"), - tr("Enter the URL of the tracker to add:"), - QLineEdit::Normal, QString(), &ok); + auto input = QInputDialog::getText( + this, + tr("Add Tracker"), + tr("Enter the URL of the tracker to add:"), + QLineEdit::Normal, {}, &ok); + if (ok && !input.isEmpty()) { m_torrent->addTracker(input); } @@ -737,10 +733,10 @@ void TorrentWidget::addTracker() void TorrentWidget::removeTracker() { - QModelIndexList selection = ui->trackerTableView->selectionModel()->selectedRows(); - for (int i = 0; i < selection.count(); ++i) { - QModelIndex index = selection.at(i); - int row = index.row(); + auto selection = ui->trackerTableView->selectionModel()->selectedRows(); + for (auto i = 0; i < selection.count(); ++i) { + auto index = selection.at(i); + auto row = index.row(); m_torrent->removeTrackerAt(row); } } @@ -748,17 +744,15 @@ void TorrentWidget::removeTracker() void TorrentWidget::copyTrackerList() { QStringList urls; - foreach (const TorrentTrackerInfo &tracker, m_torrent->detail().trackers) { + for (auto tracker : m_torrent->detail().trackers) { urls << tracker.url; } QString text; - foreach (auto url, urls) { + for (auto url : urls) { text += url; text += QChar::LineFeed; } - QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(text); - + QApplication::clipboard()->setText(text); } /****************************************************************************** @@ -768,9 +762,9 @@ void TorrentWidget::resetUi() if (m_torrent) { m_torrent->retranslateUi(); - QAbstractTableModel* fileModel = m_torrent->fileModel(); - QAbstractTableModel* peerModel = m_torrent->peerModel(); - QAbstractTableModel* trackerModel = m_torrent->trackerModel(); + auto fileModel = m_torrent->fileModel(); + auto peerModel = m_torrent->peerModel(); + auto trackerModel = m_torrent->trackerModel(); Q_ASSERT(fileTableHeaders.count() == fileModel->columnCount()); Q_ASSERT(peerTableHeaders.count() == peerModel->columnCount()); @@ -785,7 +779,7 @@ void TorrentWidget::resetUi() setColumnWidths(ui->trackerTableView, m_trackerColumnsWidths); // hide column - ui->fileTableView->hideColumn(file_table_hidden_column_index); + ui->fileTableView->hideColumn(FILE_TABLE_HIDDEN_COLUMN_INDEX); } else { @@ -793,9 +787,9 @@ void TorrentWidget::resetUi() getColumnWidths(ui->peerTableView, &m_peerColumnsWidths); getColumnWidths(ui->trackerTableView, &m_trackerColumnsWidths); - ui->fileTableView->setModel(Q_NULLPTR); - ui->peerTableView->setModel(Q_NULLPTR); - ui->trackerTableView->setModel(Q_NULLPTR); + ui->fileTableView->setModel(nullptr); + ui->peerTableView->setModel(nullptr); + ui->trackerTableView->setModel(nullptr); } updateWidget(); @@ -850,8 +844,8 @@ void TorrentWidget::updateTorrentPage() if (!m_torrent) { return; } - const TorrentMetaInfo &mi = m_torrent->metaInfo(); - const TorrentInfo &ti = m_torrent->info(); + auto mi = m_torrent->metaInfo(); + auto ti = m_torrent->info(); auto wasted = tr("%0 (%1 hashfails)").arg( Format::fileSizeToString(ti.bytesFailed + ti.bytesRedundant), @@ -876,7 +870,7 @@ void TorrentWidget::updateTorrentPage() text(mi.peersInSwarm)); auto shareRatio = text(QString("0.000")); - auto status = text(m_torrent ? m_torrent->status() : QString()); + auto status = text(m_torrent ? m_torrent->status() : ""_L1); auto pieces = tr("%0 x %1").arg( text(mi.initialMetaInfo.pieceCount), @@ -920,7 +914,7 @@ void TorrentWidget::getColumnWidths(QTableView *view, QList *widths) { if (view && view->model() && view->model()->columnCount() > 0) { widths->clear(); - for (int column = 0, count = view->model()->columnCount(); column < count; ++column) { + for (auto column = 0; column < view->model()->columnCount(); ++column) { auto width = view->columnWidth(column); widths->append(width); } @@ -930,12 +924,12 @@ void TorrentWidget::getColumnWidths(QTableView *view, QList *widths) void TorrentWidget::setColumnWidths(QTableView *view, const QList &widths) { if (view && view->model()) { - for (int column = 0, count = view->model()->columnCount(); column < count; ++column) { + for (auto column = 0; column < view->model()->columnCount(); ++column) { if (column < widths.count()) { auto width = widths.at(column); view->setColumnWidth(column, width); } else { - view->setColumnWidth(column, column_default_width); + view->setColumnWidth(column, COLUMN_DEFAULT_WIDTH); } } } @@ -945,7 +939,7 @@ void TorrentWidget::setColumnWidths(QTableView *view, const QList &widths) ******************************************************************************/ inline QString TorrentWidget::text(int value, bool showInfiniteSymbol) { - const QString defaultSymbol = showInfiniteSymbol ? Format::infinity() : QString("-"); + auto defaultSymbol = showInfiniteSymbol ? Format::infinity() : "-"_L1; return value < 0 ? defaultSymbol : QString::number(value); @@ -953,14 +947,10 @@ inline QString TorrentWidget::text(int value, bool showInfiniteSymbol) inline QString TorrentWidget::text(const QString &text) { - return text.isNull() || text.isEmpty() - ? QString("-") - : text; + return text.isEmpty() ? "-"_L1 : text; } inline QString TorrentWidget::text(const QDateTime &datetime) { - return datetime.isNull() || !datetime.isValid() - ? QString("-") - : datetime.toString("dd/MM/yy HH:mm:ss"); + return !datetime.isValid() ? "-"_L1 : datetime.toString("dd/MM/yy HH:mm:ss"_L1); } diff --git a/src/widgets/torrentwidget.h b/src/widgets/torrentwidget.h index b8f8ad24..61d5e047 100644 --- a/src/widgets/torrentwidget.h +++ b/src/widgets/torrentwidget.h @@ -38,7 +38,7 @@ class TorrentWidget : public QWidget Q_OBJECT public: explicit TorrentWidget(QWidget *parent); - ~TorrentWidget() Q_DECL_OVERRIDE; + ~TorrentWidget() override; TorrentBaseContext* torrentContext() const; void setTorrentContext(TorrentBaseContext *torrentContext); @@ -53,7 +53,7 @@ class TorrentWidget : public QWidget bool restoreState(const QByteArray &state, int version = 0); protected slots: - void changeEvent(QEvent *event) Q_DECL_OVERRIDE; + void changeEvent(QEvent *event) override; private slots: void onChanged(); @@ -82,12 +82,12 @@ private slots: private: Ui::TorrentWidget *ui; - TorrentBaseContext *m_torrentContext; - Torrent *m_torrent; + TorrentBaseContext *m_torrentContext = nullptr; + Torrent *m_torrent = nullptr; - QList m_fileColumnsWidths; - QList m_peerColumnsWidths; - QList m_trackerColumnsWidths; + QList m_fileColumnsWidths = {}; + QList m_peerColumnsWidths = {}; + QList m_trackerColumnsWidths = {}; void resetUi(); void retranslateUi(); @@ -120,10 +120,9 @@ class FileTableViewItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit FileTableViewItemDelegate(QObject *parent = Q_NULLPTR); + explicit FileTableViewItemDelegate(QObject *parent = nullptr); - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index ) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; }; /****************************************************************************** @@ -135,10 +134,9 @@ class PeerTableViewItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit PeerTableViewItemDelegate(QObject *parent = Q_NULLPTR); + explicit PeerTableViewItemDelegate(QObject *parent = nullptr); - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index ) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; }; /****************************************************************************** @@ -147,10 +145,9 @@ class TrackerTableViewItemDelegate : public QStyledItemDelegate { Q_OBJECT public: - explicit TrackerTableViewItemDelegate(QObject *parent = Q_NULLPTR); + explicit TrackerTableViewItemDelegate(QObject *parent = nullptr); - void paint(QPainter *painter, const QStyleOptionViewItem &option, - const QModelIndex &index ) const Q_DECL_OVERRIDE; + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const override; }; #endif // WIDGETS_TORRENT_WIDGET_H diff --git a/src/widgets/urlformwidget.cpp b/src/widgets/urlformwidget.cpp index f1379c86..facca516 100644 --- a/src/widgets/urlformwidget.cpp +++ b/src/widgets/urlformwidget.cpp @@ -68,8 +68,7 @@ void UrlFormWidget::setExternalUrlLabelAndLineEdit(QLabel *urlLabel, QLineEdit * ui->urlLabel->setText(urlLabel->text()); ui->urlLineEdit->setText(urlLineEdit->text()); - connect(urlLineEdit, SIGNAL(textChanged(const QString &)), - ui->urlLineEdit, SLOT(setText(const QString &))); + connect(urlLineEdit, SIGNAL(textChanged(QString)), ui->urlLineEdit, SLOT(setText(QString))); urlLabel->setMinimumWidth(ui->urlLabel->width()); } @@ -151,7 +150,7 @@ QString UrlFormWidget::url() const const QUrl url(ui->urlLineEdit->text()); // Remove trailing / and \ and . in the given text. - const QString adjusted = url.adjusted(QUrl::StripTrailingSlash).toString(); + auto adjusted = url.adjusted(QUrl::StripTrailingSlash).toString(); return adjusted; } diff --git a/src/widgets/urlformwidget.h b/src/widgets/urlformwidget.h index 61edce69..0b94c327 100644 --- a/src/widgets/urlformwidget.h +++ b/src/widgets/urlformwidget.h @@ -32,8 +32,8 @@ class UrlFormWidget : public QWidget { Q_OBJECT public: - explicit UrlFormWidget(QWidget *parent = Q_NULLPTR); - ~UrlFormWidget() Q_DECL_OVERRIDE; + explicit UrlFormWidget(QWidget *parent = nullptr); + ~UrlFormWidget() override; void setExternalUrlLabelAndLineEdit(QLabel *urlLabel, QLineEdit *urlLineEdit); void setReferringPage(const QString &referringPage); diff --git a/src/widgets/urllineedit.h b/src/widgets/urllineedit.h index 62a66f64..50ef8f4a 100644 --- a/src/widgets/urllineedit.h +++ b/src/widgets/urllineedit.h @@ -23,8 +23,8 @@ class UrlLineEdit : public QLineEdit { Q_OBJECT public: - explicit UrlLineEdit(QWidget *parent = Q_NULLPTR); - ~UrlLineEdit() Q_DECL_OVERRIDE = default; + explicit UrlLineEdit(QWidget *parent = nullptr); + ~UrlLineEdit() override = default; }; #endif // WIDGETS_URL_LINE_EDIT_H diff --git a/test/core/downloadengine/tst_downloadengine.cpp b/test/core/downloadengine/tst_downloadengine.cpp index 77c0e71c..5d56d426 100644 --- a/test/core/downloadengine/tst_downloadengine.cpp +++ b/test/core/downloadengine/tst_downloadengine.cpp @@ -105,7 +105,7 @@ static void VERIFY_ORDER(const QScopedPointer &engine, QListdownloadItems().size() != indexes.size()) { QFAIL("Sizes must be the same"); } - for (int i = 0, total = indexes.size(); i < total; ++i) { + for (auto i = 0; i < indexes.size(); ++i) { auto expected = QString("item %0").arg(indexes.at(i)); auto actual = items.at(i)->localFileName(); if (actual != expected) { @@ -131,7 +131,7 @@ static void select(const QScopedPointer &engine, QList inde { Q_ASSERT(!engine.isNull()); QList selection; - for (int i = 0, total = indexes.size(); i < total; ++i) { + for (auto i = 0; i < indexes.size(); ++i) { auto index = indexes.at(i); selection.append(engine->downloadItems().at(index)); } diff --git a/test/core/torrentcontext/tst_torrentcontext.cpp b/test/core/torrentcontext/tst_torrentcontext.cpp index 1cb89013..135c9041 100644 --- a/test/core/torrentcontext/tst_torrentcontext.cpp +++ b/test/core/torrentcontext/tst_torrentcontext.cpp @@ -87,7 +87,7 @@ void tst_TorrentContext::toBitArray() // Given QFETCH(QBitArray, input); lt::typed_bitfield pieces(input.size(), false); - for (int i = 0; i < input.size(); ++i) { + for (auto i = 0; i < input.size(); ++i) { if (input.testBit(i)) { pieces.set_bit(static_cast(i)); } diff --git a/test/manual-test/demo/mainwindow.cpp b/test/manual-test/demo/mainwindow.cpp index 3af2a1ab..0f04fe68 100644 --- a/test/manual-test/demo/mainwindow.cpp +++ b/test/manual-test/demo/mainwindow.cpp @@ -40,7 +40,6 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) , ui(new Ui::MainWindow) , m_downloadManager(new FakeDownloadManager(this)) - { ui->setupUi(this); @@ -51,15 +50,10 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent) /* Connect the SceneManager to the MainWindow. */ /* The SceneManager centralizes the changes. */ - QObject::connect(m_downloadManager, SIGNAL(jobAppended(DownloadRange)), - this, SLOT(onJobAddedOrRemoved(DownloadRange))); - QObject::connect(m_downloadManager, SIGNAL(jobRemoved(DownloadRange)), - this, SLOT(onJobAddedOrRemoved(DownloadRange))); - QObject::connect(m_downloadManager, SIGNAL(jobStateChanged(IDownloadItem*)), - this, SLOT(onJobStateChanged(IDownloadItem*))); - QObject::connect(m_downloadManager, SIGNAL(selectionChanged()), - this, SLOT(onSelectionChanged())); - + QObject::connect(m_downloadManager, SIGNAL(jobAppended(DownloadRange)), this, SLOT(onJobAddedOrRemoved(DownloadRange))); + QObject::connect(m_downloadManager, SIGNAL(jobRemoved(DownloadRange)), this, SLOT(onJobAddedOrRemoved(DownloadRange))); + QObject::connect(m_downloadManager, SIGNAL(jobStateChanged(IDownloadItem*)), this, SLOT(onJobStateChanged(IDownloadItem*))); + QObject::connect(m_downloadManager, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged())); /* Connect the rest of the GUI widgets together (selection, focus, etc.) */ createActions(); @@ -172,7 +166,7 @@ void MainWindow::createContextMenu() void MainWindow::propagateIcons() { - const QMap map = { + const QHash hash = { //! [0] File // {ui->actionHome , "home"}, @@ -251,7 +245,7 @@ void MainWindow::propagateIcons() // {ui->actionAboutYoutubeDL , ""} //! [5] }; - Theme::setIcons(this, map); + Theme::setIcons(this, hash); } /****************************************************************************** @@ -269,7 +263,7 @@ void MainWindow::selectNone() void MainWindow::invertSelection() { QList inverted; - foreach (auto item, m_downloadManager->downloadItems()) { + for (auto item : m_downloadManager->downloadItems()) { if (!m_downloadManager->isSelected(item)) { inverted.append(item); } @@ -339,21 +333,21 @@ void MainWindow::add() void MainWindow::resume() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->resume(item); } } void MainWindow::cancel() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->cancel(item); } } void MainWindow::pause() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { m_downloadManager->pause(item); } } @@ -390,7 +384,7 @@ void MainWindow::addDomainSpecificLimit() void MainWindow::forceStart() { - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { /// todo Maybe run the item instantly (in a higher priority queue?) m_downloadManager->cancel(item); m_downloadManager->resume(item); @@ -422,11 +416,11 @@ void MainWindow::refreshTitleAndStatus() ? QString("~%0").arg(Format::currentSpeedToString(speed)) : QString(); - const int completedCount = m_downloadManager->completedJobs().count(); - // const int runningCount = m_downloadManager->runningJobs().count(); - const int failedCount = m_downloadManager->failedJobs().count(); - const int count = m_downloadManager->count(); - const int doneCount = completedCount + failedCount; + auto completedCount = m_downloadManager->completedJobs().count(); + // auto runningCount = m_downloadManager->runningJobs().count(); + auto failedCount = m_downloadManager->failedJobs().count(); + auto count = m_downloadManager->count(); + auto doneCount = completedCount + failedCount; auto windowTitle = QString("%0 %1/%2 - %3") .arg(totalSpeed).arg(doneCount).arg(count) @@ -437,18 +431,18 @@ void MainWindow::refreshTitleAndStatus() void MainWindow::refreshMenus() { - const bool hasJobs = !m_downloadManager->downloadItems().isEmpty(); - const bool hasSelection = !m_downloadManager->selection().isEmpty(); - // const bool hasOnlyOneSelected = m_downloadManager->selection().count() == 1; - //bool hasOnlyCompletedSelected = hasSelection; - //foreach (auto item, m_downloadManager->selection()) { + auto hasJobs = !m_downloadManager->downloadItems().isEmpty(); + auto hasSelection = !m_downloadManager->selection().isEmpty(); + //auto hasOnlyOneSelected = m_downloadManager->selection().count() == 1; + //auto hasOnlyCompletedSelected = hasSelection; + //for (auto item : m_downloadManager->selection()) { // if (item->state() != IDownloadItem::Completed) { // hasOnlyCompletedSelected = false; // continue; // } //} bool hasAtLeastOneUncompletedSelected = false; - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { if (item->state() != IDownloadItem::Completed) { hasAtLeastOneUncompletedSelected = true; continue; @@ -457,7 +451,7 @@ void MainWindow::refreshMenus() bool hasResumableSelection = false; bool hasPausableSelection = false; bool hasCancelableSelection = false; - foreach (auto item, m_downloadManager->selection()) { + for (auto item : m_downloadManager->selection()) { if (item->isResumable()) { hasResumableSelection = true; } diff --git a/test/manual-test/demo/mainwindow.h b/test/manual-test/demo/mainwindow.h index f9b9ef89..fda03b8a 100644 --- a/test/manual-test/demo/mainwindow.h +++ b/test/manual-test/demo/mainwindow.h @@ -33,7 +33,7 @@ class MainWindow : public QMainWindow Q_OBJECT public: - explicit MainWindow(QWidget *parent = Q_NULLPTR); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); public slots: diff --git a/test/manual-test/streamwidget/mainwindow.cpp b/test/manual-test/streamwidget/mainwindow.cpp index 060ad953..5d83e4be 100644 --- a/test/manual-test/streamwidget/mainwindow.cpp +++ b/test/manual-test/streamwidget/mainwindow.cpp @@ -132,7 +132,7 @@ void MainWindow::onPlaylistButtonClicked() list << DummyStreamFactory::createDummyStreamObject_Dailymotion(); list << DummyStreamFactory::createDummyStreamObject_unavailable(); list << DummyStreamFactory::createDummyStreamObject_Other(); - for (int i = 0; i < list.count(); ++i) { + for (auto i = 0; i < list.count(); ++i) { auto item = list.at(i); item.data().playlist = QLatin1String("Playlist of favorite streams"); item.data().playlist_index = QString::number(i + 1); diff --git a/test/manual-test/streamwidget/mainwindow.h b/test/manual-test/streamwidget/mainwindow.h index 4b06d8a0..d92ab585 100644 --- a/test/manual-test/streamwidget/mainwindow.h +++ b/test/manual-test/streamwidget/mainwindow.h @@ -29,7 +29,7 @@ class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(QWidget *parent = Q_NULLPTR); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private slots: diff --git a/test/manual-test/texteditorwidget/mainwindow.h b/test/manual-test/texteditorwidget/mainwindow.h index 0e4ca56d..66fd723a 100644 --- a/test/manual-test/texteditorwidget/mainwindow.h +++ b/test/manual-test/texteditorwidget/mainwindow.h @@ -27,7 +27,7 @@ class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(QWidget *parent = Q_NULLPTR); + explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: diff --git a/test/manual-test/torrentwidget/mainwindow.cpp b/test/manual-test/torrentwidget/mainwindow.cpp index c72b64b4..b04d451f 100644 --- a/test/manual-test/torrentwidget/mainwindow.cpp +++ b/test/manual-test/torrentwidget/mainwindow.cpp @@ -87,7 +87,7 @@ void MainWindow::onCompletedClicked() void MainWindow::onRandomClicked() { m_animator->stop(); - const int percent = Utils::randomBetween(1, 100); + auto percent = Utils::randomBetween(1, 100); m_animator->setProgress(percent); } diff --git a/test/manual-test/torrentwidget/mainwindow.h b/test/manual-test/torrentwidget/mainwindow.h index 05fa47ba..ffd587b6 100644 --- a/test/manual-test/torrentwidget/mainwindow.h +++ b/test/manual-test/torrentwidget/mainwindow.h @@ -32,8 +32,8 @@ class MainWindow : public QMainWindow { Q_OBJECT public: - explicit MainWindow(QWidget *parent = Q_NULLPTR); - ~MainWindow() Q_DECL_OVERRIDE; + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow() override; private slots: void onStartClicked(); diff --git a/test/manual-test/webengine/mainwindow.cpp b/test/manual-test/webengine/mainwindow.cpp index 78379c2b..d2146c4b 100644 --- a/test/manual-test/webengine/mainwindow.cpp +++ b/test/manual-test/webengine/mainwindow.cpp @@ -37,8 +37,6 @@ InvokeWrapper invoke(R *receiver, void (C::*memberFun)(Arg)) MainWindow::MainWindow(const QUrl& url) { - progress = 0; - QFile file; file.setFileName(":/jquery.min.js"); file.open(QIODevice::ReadOnly); @@ -122,7 +120,7 @@ void MainWindow::adjustLocation() void MainWindow::changeLocation() { - QUrl url = QUrl::fromUserInput(locationEdit->text()); + auto url = QUrl::fromUserInput(locationEdit->text()); view->load(url); view->setFocus(); } diff --git a/test/manual-test/webengine/mainwindow.h b/test/manual-test/webengine/mainwindow.h index 6dbdc0e5..af739026 100644 --- a/test/manual-test/webengine/mainwindow.h +++ b/test/manual-test/webengine/mainwindow.h @@ -49,11 +49,11 @@ protected slots: void removeEmbeddedElements(); private: - QString jQuery; - QWebEngineView *view; - QLineEdit *locationEdit; - QAction *rotateAction; - int progress; + QString jQuery = {}; + QWebEngineView *view = nullptr; + QLineEdit *locationEdit = nullptr; + QAction *rotateAction = nullptr; + int progress = 0; }; diff --git a/test/utils/dummytorrentanimator.cpp b/test/utils/dummytorrentanimator.cpp index 5be11807..59e82791 100644 --- a/test/utils/dummytorrentanimator.cpp +++ b/test/utils/dummytorrentanimator.cpp @@ -25,10 +25,10 @@ #include #include -constexpr int msec_file_refresh = 10; -constexpr int msec_peer_refresh = 500; -constexpr qsizetype piece_size = 32*1024*8; -constexpr qsizetype max_torrent_size = 1024*1024; +constexpr int MSEC_FILE_REFRESH = 10; +constexpr int MSEC_PEER_REFRESH = 500; +constexpr qsizetype PIECE_SIZE = 32*1024*8; +constexpr qsizetype MAX_TORRENT_SIZE = 1024*1024; namespace Utils { /*! @@ -155,12 +155,12 @@ QBitArray DummyTorrentAnimator::createRandomBitArray(int size, int percent) } QBitArray ba = QBitArray(size, false); if (percent == 50) { - for (int i = 0; i < size; i+=2) { + for (auto i = 0; i < size; i+=2) { ba.setBit(i); } } else { - for (int i = 0; i < size; ++i) { - const int v = Utils::randomBetween(0, 100); + for (auto i = 0; i < size; ++i) { + auto v = Utils::randomBetween(0, 100); if (v <= percent) { ba.setBit(i); } @@ -184,8 +184,8 @@ void DummyTorrentAnimator::start() } randomize(); - m_fileTimer.start(msec_file_refresh); - m_peerTimer.start(msec_peer_refresh); + m_fileTimer.start(MSEC_FILE_REFRESH); + m_peerTimer.start(MSEC_PEER_REFRESH); emit started(true); } @@ -204,7 +204,7 @@ void DummyTorrentAnimator::animate() if (m_ticks.count() != m_timeouts.count()) { m_ticks = m_timeouts; } - for (int i = 0, total = m_ticks.count(); i < total; ++i) { + for (auto i = 0; i < m_ticks.count(); ++i) { m_ticks[i]--; if (m_ticks[i] <= 0) { m_ticks[i] = m_timeouts[i]; @@ -225,14 +225,14 @@ void DummyTorrentAnimator::animateFile(int index) qsizetype bytesTotal = metaInfo.initialMetaInfo.files.at(index).bytesTotal; TorrentHandleInfo detail = m_torrent->detail(); - detail.files[index].bytesReceived += piece_size; + detail.files[index].bytesReceived += PIECE_SIZE; detail.files[index].bytesReceived = qMin(detail.files[index].bytesReceived, bytesTotal); TorrentInfo info = m_torrent->info(); - info.bytesReceived += piece_size; + info.bytesReceived += PIECE_SIZE; info.bytesReceived = qMin(info.bytesReceived, info.bytesTotal); - info.bytesSessionDownloaded += piece_size; - info.bytesSessionUploaded += piece_size >> 2; + info.bytesSessionDownloaded += PIECE_SIZE; + info.bytesSessionUploaded += PIECE_SIZE >> 2; info.state = TorrentInfo::downloading; m_torrent->setInfo(info, false); @@ -252,12 +252,12 @@ void DummyTorrentAnimator::animatePieces() void DummyTorrentAnimator::animatePeers() { static int counter = 0; - counter += msec_peer_refresh; - const TorrentInfo info = m_torrent->info(); - const int total_pieces_count = info.downloadedPieces.count(); + counter += MSEC_PEER_REFRESH; + auto info = m_torrent->info(); + auto total_pieces_count = info.downloadedPieces.count(); TorrentHandleInfo detail = m_torrent->detail(); - const int count = detail.peers.count(); + auto count = detail.peers.count(); if (count >= 10) { for (int i = 0; i < 7; ++i) { @@ -285,8 +285,8 @@ void DummyTorrentAnimator::animatePeers() QString::number(Utils::randomBetween(1, 65535))); auto fct = DummyTorrentFactory::createDummyPeer2; detail.peers << fct(EndPoint(randomIP), "XXXXXX--X-", "", total_pieces_count, - (max_torrent_size / 1024) * Utils::randomBetweenLog(0, 1024), - (max_torrent_size / 1024) * Utils::randomBetweenLog(0, 1024)); + (MAX_TORRENT_SIZE / 1024) * Utils::randomBetweenLog(0, 1024), + (MAX_TORRENT_SIZE / 1024) * Utils::randomBetweenLog(0, 1024)); } m_torrent->setDetail(detail, false); // emit changed } @@ -295,7 +295,7 @@ void DummyTorrentAnimator::animatePeers() ******************************************************************************/ void DummyTorrentAnimator::setPiecesRandomly(QBitArray &pieces) { - const int count = pieces.count(); + auto count = pieces.count(); if (pieces.count(true) > count - 10) { pieces.fill(true); return; @@ -303,7 +303,7 @@ void DummyTorrentAnimator::setPiecesRandomly(QBitArray &pieces) // turn random bits to 1 for (int i = 0; i < 3; ++i) { - const int index = Utils::randomBetween(0, count - 1); + auto index = Utils::randomBetween(0, count - 1); pieces.setBit(index); } @@ -324,11 +324,11 @@ void DummyTorrentAnimator::setPiecesRandomly(QBitArray &pieces) void DummyTorrentAnimator::randomize() { Q_ASSERT(m_torrent); - int total = m_torrent->metaInfo().initialMetaInfo.files.count(); + auto total = m_torrent->metaInfo().initialMetaInfo.files.count(); m_timeouts.clear(); m_ticks.clear(); - for (int i = 0; i < total; ++i) { - int timeout = msec_file_refresh * Utils::randomBetween(1, 10); + for (auto i = 0; i < total; ++i) { + auto timeout = MSEC_FILE_REFRESH * Utils::randomBetween(1, 10); m_timeouts << timeout; } } diff --git a/test/utils/dummytorrentanimator.h b/test/utils/dummytorrentanimator.h index 1d41068d..bafa5f3e 100644 --- a/test/utils/dummytorrentanimator.h +++ b/test/utils/dummytorrentanimator.h @@ -31,7 +31,7 @@ class DummyTorrentAnimator : public QObject { Q_OBJECT public: - DummyTorrentAnimator(QObject *parent = Q_NULLPTR); + DummyTorrentAnimator(QObject *parent = nullptr); Torrent* torrent() const; void setTorrent(Torrent *torrent); @@ -49,7 +49,7 @@ private slots: void animate(); private: - Torrent *m_torrent{Q_NULLPTR}; + Torrent *m_torrent{nullptr}; QTimer m_fileTimer; QTimer m_peerTimer; QList m_timeouts; diff --git a/test/utils/dummytorrentfactory.cpp b/test/utils/dummytorrentfactory.cpp index d0039cc8..5008812a 100644 --- a/test/utils/dummytorrentfactory.cpp +++ b/test/utils/dummytorrentfactory.cpp @@ -75,7 +75,7 @@ TorrentPtr TorrentSkeleton::toTorrent(QObject *parent) TorrentPtr t(new Torrent(parent)); qsizetype total_size_in_KB = 0; - foreach (auto basicFile, m_basicFiles) { + for (auto basicFile : m_basicFiles) { total_size_in_KB += basicFile.size_in_KB; } qint64 total_pieces_count = static_cast(qreal(total_size_in_KB) / m_piece_size_in_KB); @@ -89,7 +89,7 @@ TorrentPtr TorrentSkeleton::toTorrent(QObject *parent) QString magnetLink; magnetLink = QString("magnet:?xt=urn:btih:%0&dn=%1").arg( infohash, m_name.replace(".zip", "-ZIP")); - foreach (auto tracker, trackers) { + for (auto tracker : trackers) { magnetLink += QString("&tr=%0") .arg(tracker.replace(':', "%3A").replace('/', "%2F")); } @@ -117,7 +117,7 @@ TorrentPtr TorrentSkeleton::toTorrent(QObject *parent) qsizetype offset_in_KB = 0; - foreach (auto file, m_basicFiles) { + for (auto file : m_basicFiles) { TorrentFileMetaInfo::Flags flags; if (file.name.contains(".exe")) { @@ -157,7 +157,7 @@ TorrentPtr TorrentSkeleton::toTorrent(QObject *parent) detail.peers << fct(EndPoint("86.120.101.138:42624"), "XA--------", "", total_pieces_count); detail.peers << fct(EndPoint("175.158.201.29:32725"), "XXXXXX--X-", "", total_pieces_count); - foreach (auto tracker, trackers) { + for (auto tracker : trackers) { detail.trackers << TorrentTrackerInfo(tracker); } @@ -219,19 +219,19 @@ TorrentPtr DummyTorrentFactory::createDummyTorrent(QObject *parent) ******************************************************************************/ static QBitArray toAvailablePieces(qsizetype size, const QString &pieceSketch) { - QBitArray ba = QBitArray(size, false); - const qsizetype count = pieceSketch.count(); - const qsizetype sectionSize = static_cast(qreal(size) / count); + auto ba = QBitArray(size, false); + auto count = pieceSketch.count(); + auto sectionSize = static_cast(qreal(size) / count); for (auto i = 0; i < count; ++i) { auto sectionBegin = i * sectionSize; auto sectionEnd = qMin(size, (i + 1) * sectionSize); auto ch = pieceSketch.at(i); if (ch == QLatin1Char('X')) { - for (int j = sectionBegin; j < sectionEnd; ++j) { + for (auto j = sectionBegin; j < sectionEnd; ++j) { ba.setBit(j); } } else if (ch == QLatin1Char('A')) { - for (int j = sectionBegin; j < sectionEnd; j += 2) { + for (auto j = sectionBegin; j < sectionEnd; j += 2) { ba.setBit(j); } } diff --git a/test/utils/fakedownloaditem.h b/test/utils/fakedownloaditem.h index 83d8f42a..c0bc35c1 100644 --- a/test/utils/fakedownloaditem.h +++ b/test/utils/fakedownloaditem.h @@ -29,33 +29,33 @@ class FakeDownloadItem : public AbstractDownloadItem Q_OBJECT public: - explicit FakeDownloadItem(QObject *parent = Q_NULLPTR); - explicit FakeDownloadItem(QString localFileName, QObject *parent = Q_NULLPTR); + explicit FakeDownloadItem(QObject *parent = nullptr); + explicit FakeDownloadItem(QString localFileName, QObject *parent = nullptr); explicit FakeDownloadItem( QUrl url, QString filename, qsizetype bytesTotal, qint64 timeIncrement, qint64 duration, - QObject *parent= Q_NULLPTR); + QObject *parent= nullptr); - ~FakeDownloadItem() Q_DECL_OVERRIDE; + ~FakeDownloadItem() override; - virtual QUrl sourceUrl() const Q_DECL_OVERRIDE; + virtual QUrl sourceUrl() const override; void setSourceUrl(const QUrl &resourceUrl); - virtual QString localFileName() const Q_DECL_OVERRIDE; + virtual QString localFileName() const override; - virtual QString localFullFileName() const Q_DECL_OVERRIDE; - virtual QString localFilePath() const Q_DECL_OVERRIDE; + virtual QString localFullFileName() const override; + virtual QString localFilePath() const override; - virtual QUrl localFileUrl() const Q_DECL_OVERRIDE; - virtual QUrl localDirUrl() const Q_DECL_OVERRIDE; + virtual QUrl localFileUrl() const override; + virtual QUrl localDirUrl() const override; public slots: - virtual void resume() Q_DECL_OVERRIDE; - virtual void pause() Q_DECL_OVERRIDE; - virtual void stop() Q_DECL_OVERRIDE; + virtual void resume() override; + virtual void pause() override; + virtual void stop() override; private slots: diff --git a/test/utils/fakedownloadmanager.cpp b/test/utils/fakedownloadmanager.cpp index 2f6fd695..21bb8b72 100644 --- a/test/utils/fakedownloadmanager.cpp +++ b/test/utils/fakedownloadmanager.cpp @@ -36,8 +36,8 @@ IDownloadItem* FakeDownloadManager::createItem(const QUrl &url) void FakeDownloadManager::createFakeJobs(int count) { QList items; - for (int i = 0; i < count; ++i) { - FakeDownloadItem *item = new FakeDownloadItem(this); + for (auto i = 0; i < count; ++i) { + auto item = new FakeDownloadItem(this); items.append(item); } DownloadEngine::append(items, false); diff --git a/test/utils/fakedownloadmanager.h b/test/utils/fakedownloadmanager.h index dc5a4bb4..80c8fb4e 100644 --- a/test/utils/fakedownloadmanager.h +++ b/test/utils/fakedownloadmanager.h @@ -24,10 +24,10 @@ class FakeDownloadManager : public DownloadEngine Q_OBJECT public: - explicit FakeDownloadManager(QObject *parent = Q_NULLPTR); + explicit FakeDownloadManager(QObject *parent = nullptr); ~FakeDownloadManager(); - virtual IDownloadItem* createItem(const QUrl &url) Q_DECL_OVERRIDE; + virtual IDownloadItem* createItem(const QUrl &url) override; /* Utility */ void createFakeJobs(int count = 100); diff --git a/version b/version index 818bd47a..fd2a0186 100644 --- a/version +++ b/version @@ -1 +1 @@ -3.0.6 +3.1.0 diff --git a/web-extension/launcher/launcher.cpp b/web-extension/launcher/launcher.cpp index 06f2c665..96736b37 100644 --- a/web-extension/launcher/launcher.cpp +++ b/web-extension/launcher/launcher.cpp @@ -235,11 +235,7 @@ static bool startInteractiveMode(const QString &program) #endif // Start the Application, detached from the Launcher -#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) return process.startDetached(); -#else - return process.startDetached(program, QStringList() << "-i"); -#endif } static bool sendCommandToProcess(const QString &program, const QString &arguments)