diff --git a/.travis.yml b/.travis.yml index c4f95afb2..7ec2bf611 100644 --- a/.travis.yml +++ b/.travis.yml @@ -93,7 +93,7 @@ script: - cd ../examples - bjam --hash -j3 warnings-as-errors=on variant=$variant $toolset link=shared - - if [[ lang == "cpp11" ]]; then + - if [[ $lang == "cpp11" ]]; then bjam --hash -j3 warnings-as-errors=on variant=$variant $toolset link=shared bt-get bt-get2; fi - cd .. diff --git a/CMakeLists.txt b/CMakeLists.txt index 46b6f0a6f..ea49d573c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ set(sources torrent_info torrent_peer torrent_peer_allocator + torrent_status tracker_manager http_tracker_connection utf8 diff --git a/Jamfile b/Jamfile index 1ee657652..53ba83e5f 100644 --- a/Jamfile +++ b/Jamfile @@ -626,6 +626,7 @@ SOURCES = torrent_info torrent_peer torrent_peer_allocator + torrent_status time tracker_manager http_tracker_connection diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index c909ac5f7..da853e1f2 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -21,6 +21,7 @@ EXTRA_DIST = \ src/module.cpp \ src/optional.hpp \ src/peer_info.cpp \ + src/boost_python.hpp \ src/session.cpp \ src/session_settings.cpp \ src/string.cpp \ diff --git a/bindings/python/src/alert.cpp b/bindings/python/src/alert.cpp index 895a895da..1582ac227 100644 --- a/bindings/python/src/alert.cpp +++ b/bindings/python/src/alert.cpp @@ -2,20 +2,21 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include #include #include // for piece_block #include #include +#include "bytes.hpp" using namespace boost::python; using namespace libtorrent; -std::string get_buffer(read_piece_alert const& rpa) +bytes get_buffer(read_piece_alert const& rpa) { - return rpa.buffer ? std::string(rpa.buffer.get(), rpa.size) - : std::string(); + return rpa.buffer ? bytes(rpa.buffer.get(), rpa.size) + : bytes(); } tuple endpoint_to_tuple(tcp::endpoint const& ep) @@ -269,7 +270,7 @@ void bind_alert() class_, noncopyable>( "torrent_removed_alert", no_init) - .def_readonly("info_hash", &torrent_removed_alert::info_hash) + .def_readonly("info_hash", &torrent_removed_alert::info_hash) ; class_, noncopyable>( diff --git a/bindings/python/src/big_number.cpp b/bindings/python/src/big_number.cpp index 80d357d20..10e896de8 100644 --- a/bindings/python/src/big_number.cpp +++ b/bindings/python/src/big_number.cpp @@ -3,7 +3,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include "boost_python.hpp" #include "bytes.hpp" long get_hash(boost::python::object o) diff --git a/bindings/python/src/boost_python.hpp b/bindings/python/src/boost_python.hpp new file mode 100644 index 000000000..12c1f3ea2 --- /dev/null +++ b/bindings/python/src/boost_python.hpp @@ -0,0 +1,13 @@ +// Copyright Daniel Wallin 2006. Use, modification and distribution is +// subject to the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_PYTHON_HPP +#define BOOST_PYTHON_HPP + +#include +#include +#include + +#endif + diff --git a/bindings/python/src/bytes.hpp b/bindings/python/src/bytes.hpp index 640366f36..02943b92a 100644 --- a/bindings/python/src/bytes.hpp +++ b/bindings/python/src/bytes.hpp @@ -9,9 +9,16 @@ struct bytes { - bytes(std::string const& s): arr(s) {} - bytes() {} - std::string arr; + bytes(char const* s, int len): arr(s, len) {} + bytes(std::string const& s): arr(s) {} +#if __cplusplus >= 201103L + bytes(std::string&& s): arr(std::move(s)) {} + bytes(bytes const&) = default; + bytes(bytes&&) = default; + bytes& operator=(bytes&&) = default; +#endif + bytes() {} + std::string arr; }; #endif diff --git a/bindings/python/src/converters.cpp b/bindings/python/src/converters.cpp index cae84be75..b7981ce7c 100644 --- a/bindings/python/src/converters.cpp +++ b/bindings/python/src/converters.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" using namespace boost::python; diff --git a/bindings/python/src/create_torrent.cpp b/bindings/python/src/create_torrent.cpp index d8e99bed8..95f512d18 100644 --- a/bindings/python/src/create_torrent.cpp +++ b/bindings/python/src/create_torrent.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include #include #include "libtorrent/torrent_info.hpp" diff --git a/bindings/python/src/datetime.cpp b/bindings/python/src/datetime.cpp index 220607bfe..f1e91d702 100644 --- a/bindings/python/src/datetime.cpp +++ b/bindings/python/src/datetime.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include #include "optional.hpp" #include diff --git a/bindings/python/src/entry.cpp b/bindings/python/src/entry.cpp index 3d84bec79..bced76d65 100644 --- a/bindings/python/src/entry.cpp +++ b/bindings/python/src/entry.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include #include "bytes.hpp" diff --git a/bindings/python/src/error_code.cpp b/bindings/python/src/error_code.cpp index ff5e74cb0..caea76ba9 100644 --- a/bindings/python/src/error_code.cpp +++ b/bindings/python/src/error_code.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include "boost_python.hpp" using namespace boost::python; using namespace libtorrent; diff --git a/bindings/python/src/fingerprint.cpp b/bindings/python/src/fingerprint.cpp index f0346176f..27215fac4 100644 --- a/bindings/python/src/fingerprint.cpp +++ b/bindings/python/src/fingerprint.cpp @@ -3,12 +3,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include - -#include - -#include - -#include +#include "boost_python.hpp" void bind_fingerprint() { diff --git a/bindings/python/src/ip_filter.cpp b/bindings/python/src/ip_filter.cpp index 74ef2e89e..8fea1888b 100644 --- a/bindings/python/src/ip_filter.cpp +++ b/bindings/python/src/ip_filter.cpp @@ -3,7 +3,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include "boost_python.hpp" #include "gil.hpp" using namespace boost::python; diff --git a/bindings/python/src/magnet_uri.cpp b/bindings/python/src/magnet_uri.cpp index 07b1b3ca4..291791940 100644 --- a/bindings/python/src/magnet_uri.cpp +++ b/bindings/python/src/magnet_uri.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt -#include +#include "boost_python.hpp" #include #include #include @@ -17,23 +17,23 @@ extern void dict_to_add_torrent_params(dict params, add_torrent_params& p); namespace { #ifndef TORRENT_NO_DEPRECATE - torrent_handle _add_magnet_uri(lt::session& s, std::string uri, dict params) - { - add_torrent_params p; + torrent_handle _add_magnet_uri(lt::session& s, std::string uri, dict params) + { + add_torrent_params p; - dict_to_add_torrent_params(params, p); + dict_to_add_torrent_params(params, p); - allow_threading_guard guard; + allow_threading_guard guard; - p.url = uri; + p.url = uri; #ifndef BOOST_NO_EXCEPTIONS - return s.add_torrent(p); + return s.add_torrent(p); #else - error_code ec; - return s.add_torrent(p, ec); + error_code ec; + return s.add_torrent(p, ec); #endif - } + } #endif dict parse_magnet_uri_wrap(std::string const& uri) @@ -78,10 +78,10 @@ namespace { void bind_magnet_uri() { #ifndef TORRENT_NO_DEPRECATE - def("add_magnet_uri", &_add_magnet_uri); + def("add_magnet_uri", &_add_magnet_uri); #endif - def("make_magnet_uri", make_magnet_uri0); - def("make_magnet_uri", make_magnet_uri1); - def("parse_magnet_uri", parse_magnet_uri_wrap); + def("make_magnet_uri", make_magnet_uri0); + def("make_magnet_uri", make_magnet_uri1); + def("parse_magnet_uri", parse_magnet_uri_wrap); } diff --git a/bindings/python/src/optional.hpp b/bindings/python/src/optional.hpp index 63138cc68..2477924d0 100644 --- a/bindings/python/src/optional.hpp +++ b/bindings/python/src/optional.hpp @@ -5,7 +5,7 @@ #ifndef OPTIONAL_070108_HPP # define OPTIONAL_070108_HPP -# include +# include "boost_python.hpp" # include template diff --git a/bindings/python/src/peer_info.cpp b/bindings/python/src/peer_info.cpp index c72b58166..3fd7fd045 100644 --- a/bindings/python/src/peer_info.cpp +++ b/bindings/python/src/peer_info.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "boost_python.hpp" #include using namespace boost::python; diff --git a/bindings/python/src/session.cpp b/bindings/python/src/session.cpp index 9b6f5ecc9..7d5cd049c 100644 --- a/bindings/python/src/session.cpp +++ b/bindings/python/src/session.cpp @@ -29,7 +29,7 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" -#include +#include "boost_python.hpp" #include "libtorrent/aux_/disable_warnings_pop.hpp" @@ -136,7 +136,26 @@ namespace return boost::make_shared(p, flags); } - void session_set_settings(lt::session& ses, dict const& sett_dict) +#ifndef TORRENT_NO_DEPRECATE + void session_set_settings(lt::session& ses, object const& sett) + { + extract old_settings(sett); + if (old_settings.check()) + { + allow_threading_guard guard; + ses.set_settings(old_settings); + } + else + { + settings_pack p; + make_settings_pack(p, extract(sett)); + allow_threading_guard guard; + ses.apply_settings(p); + } + } +#endif + + void session_apply_settings(lt::session& ses, dict const& sett_dict) { settings_pack p; make_settings_pack(p, sett_dict); @@ -189,7 +208,16 @@ namespace { // torrent_info objects are always held by a shared_ptr in the python binding if (params.has_key("ti") && params.get("ti") != boost::python::object()) - p.ti = extract >(params["ti"]); + { + // make a copy here. We don't want to end up holding a python-owned + // object inside libtorrent. If the last reference goes out of scope + // on the C++ side, it will end up freeing the python object + // without holding the GIL and likely crash. + // https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html + p.ti = boost::make_shared( + extract(params["ti"])); + } + if (params.has_key("info_hash")) p.info_hash = sha1_hash(bytes(extract(params["info_hash"])).arr); @@ -401,20 +429,20 @@ namespace return ret; } - cache_status get_cache_info1(lt::session& s, torrent_handle h, int flags) - { - cache_status ret; - s.get_cache_info(&ret, h, flags); - return ret; - } + cache_status get_cache_info1(lt::session& s, torrent_handle h, int flags) + { + cache_status ret; + s.get_cache_info(&ret, h, flags); + return ret; + } #ifndef TORRENT_NO_DEPRECATE - cache_status get_cache_status(lt::session& s) - { - cache_status ret; - s.get_cache_info(&ret); - return ret; - } + cache_status get_cache_status(lt::session& s) + { + cache_status ret; + s.get_cache_info(&ret); + return ret; + } dict get_utp_stats(session_status const& st) { @@ -779,14 +807,11 @@ void bind_session() #ifndef TORRENT_NO_DEPRECATE .def("add_feed", &add_feed) .def("status", allow_threads(<::session::status)) - .def("set_settings", <::session::set_settings) - .def("settings", <::session::settings) - .def("get_settings", &session_get_settings) -#else .def("settings", &session_get_settings) - .def("get_settings", &session_get_settings) + .def("set_settings", &session_set_settings) #endif - .def("apply_settings", &session_set_settings) + .def("get_settings", &session_get_settings) + .def("apply_settings", &session_apply_settings) #ifndef TORRENT_NO_DEPRECATE #ifndef TORRENT_DISABLE_ENCRYPTION .def("set_pe_settings", allow_threads(<::session::set_pe_settings)) @@ -800,7 +825,7 @@ void bind_session() #ifdef TORRENT_NO_DEPRECATE , return_internal_reference<>() #endif - ) + ) .def("add_extension", &add_extension) #ifndef TORRENT_NO_DEPRECATE .def("pop_alert", &pop_alert) diff --git a/bindings/python/src/session_settings.cpp b/bindings/python/src/session_settings.cpp index b17170c07..f47418327 100644 --- a/bindings/python/src/session_settings.cpp +++ b/bindings/python/src/session_settings.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include using namespace boost::python; diff --git a/bindings/python/src/string.cpp b/bindings/python/src/string.cpp index cf3355489..6784f801c 100644 --- a/bindings/python/src/string.cpp +++ b/bindings/python/src/string.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include using namespace boost::python; diff --git a/bindings/python/src/torrent_handle.cpp b/bindings/python/src/torrent_handle.cpp index 7854c1327..59a269de3 100644 --- a/bindings/python/src/torrent_handle.cpp +++ b/bindings/python/src/torrent_handle.cpp @@ -2,8 +2,9 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include +#include #include #include #include @@ -121,59 +122,44 @@ list get_peer_info(torrent_handle const& handle) return result; } +namespace +{ + template + T extract_fn(object o) + { + return boost::python::extract(o); + } +} + void prioritize_pieces(torrent_handle& info, object o) { - std::vector result; - std::vector > piece_list; - try + stl_input_iterator begin(o), end; + if (begin == end) return; + + // determine which overload should be selected. the one taking a list of + // priorities or the one taking a list of piece -> priority mappings + bool const is_piece_list = extract >(*begin).check(); + + if (is_piece_list) { - object iter_obj = object( handle<>( PyObject_GetIter( o.ptr() ) )); - while( 1 ) - { - object obj = extract( iter_obj.attr( "next" )() ); - extract val1(obj); - if (val1.check()) - { - result.push_back(val1); - continue; - } - extract > val2(obj); - if (val2.check()) - { - piece_list.push_back(val2); - continue; - } - } + std::vector > piece_list; + std::transform(begin, end, std::back_inserter(piece_list) + , &extract_fn >); + info.prioritize_pieces(piece_list); } - catch( error_already_set ) + else { - PyErr_Clear(); - if (result.size()) - info.prioritize_pieces(result); - else - info.prioritize_pieces(piece_list); - return; + std::vector priority_vector; + std::transform(begin, end, std::back_inserter(priority_vector) + , &extract_fn); + info.prioritize_pieces(priority_vector); } } void prioritize_files(torrent_handle& info, object o) { - std::vector result; - try - { - object iter_obj = object( handle<>( PyObject_GetIter( o.ptr() ) )); - while( 1 ) - { - object obj = extract( iter_obj.attr( "next" )() ); - result.push_back(extract( obj )); - } - } - catch( error_already_set ) - { - PyErr_Clear(); - info.prioritize_files(result); - return; - } + stl_input_iterator begin(o), end; + info.prioritize_files(std::vector (begin, end)); } list file_priorities(torrent_handle& handle) diff --git a/bindings/python/src/torrent_info.cpp b/bindings/python/src/torrent_info.cpp index a7a1f476d..0ca2dd018 100644 --- a/bindings/python/src/torrent_info.cpp +++ b/bindings/python/src/torrent_info.cpp @@ -4,7 +4,7 @@ #include "libtorrent/aux_/disable_warnings_push.hpp" -#include +#include "boost_python.hpp" #include #include "libtorrent/aux_/disable_warnings_pop.hpp" @@ -90,15 +90,14 @@ namespace ti.set_merkle_tree(h); } - std::string hash_for_piece(torrent_info const& ti, int i) + bytes hash_for_piece(torrent_info const& ti, int i) { - return ti.hash_for_piece(i).to_string(); + return bytes(ti.hash_for_piece(i).to_string()); } - std::string metadata(torrent_info const& ti) + bytes metadata(torrent_info const& ti) { - std::string result(ti.metadata().get(), ti.metadata_size()); - return result; + return bytes(ti.metadata().get(), ti.metadata_size()); } list map_block(torrent_info& ti, int piece, boost::int64_t offset, int size) diff --git a/bindings/python/src/torrent_status.cpp b/bindings/python/src/torrent_status.cpp index b6e0228a2..fc74eddfa 100644 --- a/bindings/python/src/torrent_status.cpp +++ b/bindings/python/src/torrent_status.cpp @@ -2,7 +2,7 @@ // subject to the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include +#include "boost_python.hpp" #include #include #include diff --git a/bindings/python/src/utility.cpp b/bindings/python/src/utility.cpp index b9c00b5fa..a357d7fd4 100644 --- a/bindings/python/src/utility.cpp +++ b/bindings/python/src/utility.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include "boost_python.hpp" #include "bytes.hpp" using namespace boost::python; diff --git a/bindings/python/src/version.cpp b/bindings/python/src/version.cpp index a7045d020..e6234cb0e 100644 --- a/bindings/python/src/version.cpp +++ b/bindings/python/src/version.cpp @@ -3,7 +3,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#include +#include "boost_python.hpp" using namespace boost::python; using libtorrent::version; diff --git a/bindings/python/test.py b/bindings/python/test.py index 324b8cb46..3a29a06cf 100644 --- a/bindings/python/test.py +++ b/bindings/python/test.py @@ -8,7 +8,22 @@ import os import shutil import binascii -# test torrent_info +class test_torrent_handle(unittest.TestCase): + + def test_torrent_handle(self): + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + ti = lt.torrent_info('url_seed_multi.torrent'); + h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) + + h.prioritize_files([0,1]) + self.assertEqual(h.file_priorities(), [0,1]) + + h.prioritize_pieces([0]) + self.assertEqual(h.piece_priorities(), [0]) + + # also test the overload that takes a list of piece->priority mappings + h.prioritize_pieces([(0, 1)]) + self.assertEqual(h.piece_priorities(), [1]) class test_torrent_info(unittest.TestCase): @@ -24,12 +39,36 @@ class test_torrent_info(unittest.TestCase): self.assertEqual(f.file_size(0), 1234) self.assertEqual(info.total_size(), 1234) + def test_metadata(self): + ti = lt.torrent_info('base.torrent'); + + self.assertTrue(len(ti.metadata()) != 0) + self.assertTrue(len(ti.hash_for_piece(0)) != 0) + + def test_iterable_files(self): + + # this detects whether libtorrent was built with deprecated APIs + # the file_strage object is only iterable for backwards compatibility + if not hasattr(lt, 'version'): return + + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + ti = lt.torrent_info('url_seed_multi.torrent'); + files = ti.files() + + idx = 0 + expected = ['bar.txt', 'var.txt'] + for f in files: + print f.path + + self.assertEqual(os.path.split(f.path)[1], expected[idx]) + self.assertEqual(os.path.split(f.path)[0], 'temp/foo') + idx += 1 + class test_alerts(unittest.TestCase): def test_alert(self): ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) - shutil.copy(os.path.join('..', '..', 'test', 'test_torrents', 'base.torrent'), '.') ti = lt.torrent_info('base.torrent'); h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()}) st = h.status() @@ -53,6 +92,25 @@ class test_alerts(unittest.TestCase): print(st.info_hash) self.assertEqual(st.save_path, os.getcwd()) + def test_pop_alerts(self): + ses = lt.session({'alert_mask': lt.alert.category_t.all_categories}) + + ses.async_add_torrent({"ti": lt.torrent_info("base.torrent"), "save_path": "."}) +# this will cause an error (because of duplicate torrents) and the +# torrent_info object created here will be deleted once the alert goes out +# of scope. When that happens, it will decrement the python object, to allow +# it to release the object. +# we're trying to catch the error described in this post, with regards to +# torrent_info. +# https://mail.python.org/pipermail/cplusplus-sig/2007-June/012130.html + ses.async_add_torrent({"ti": lt.torrent_info("base.torrent"), "save_path": "."}) + time.sleep(1) + for i in range(0, 10): + alerts = ses.pop_alerts() + for a in alerts: + print(a.message()) + time.sleep(0.1) + class test_bencoder(unittest.TestCase): def test_bencode(self): @@ -75,6 +133,7 @@ class test_sha1hash(unittest.TestCase): class test_session(unittest.TestCase): + def test_post_session_stats(self): s = lt.session({'alert_mask': lt.alert.category_t.stats_notification}) s.post_session_stats() @@ -83,7 +142,27 @@ class test_session(unittest.TestCase): self.assertTrue(isinstance(a.values, dict)) self.assertTrue(len(a.values) > 0) + def test_deprecated_settings(self): + + # this detects whether libtorrent was built with deprecated APIs + if hasattr(lt, 'version'): + s = lt.session({}) + sett = lt.session_settings() + sett.num_want = 10; + s.set_settings(sett) + s.set_settings({'num_want': 33}) + self.assertEqual(s.get_settings()['num_want'], 33) + + def test_apply_settings(self): + + s = lt.session({}) + s.apply_settings({'num_want': 66}) + self.assertEqual(s.get_settings()['num_want'], 66) + + if __name__ == '__main__': print(lt.__version__) + shutil.copy(os.path.join('..', '..', 'test', 'test_torrents', 'url_seed_multi.torrent'), '.') + shutil.copy(os.path.join('..', '..', 'test', 'test_torrents', 'base.torrent'), '.') unittest.main() diff --git a/examples/bt-get2.cpp b/examples/bt-get2.cpp index f8db4db04..c608752c1 100644 --- a/examples/bt-get2.cpp +++ b/examples/bt-get2.cpp @@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include namespace lt = libtorrent; -using clock_t = std::chrono::monotonic_clock; +using clk = std::chrono::steady_clock; // return the name of a torrent status enum char const* state(lt::torrent_status::state_t s) @@ -75,7 +75,7 @@ int main(int argc, char const* argv[]) lt::session ses(pack); lt::add_torrent_params atp; - std::chrono::time_point last_save_resume = clock_t::now(); + 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); @@ -135,7 +135,7 @@ int main(int argc, char const* argv[]) ses.post_torrent_updates(); // save resume data once every 30 seconds - if (clock_t::now() - last_save_resume > seconds(30)) { + if (clk::now() - last_save_resume > std::chrono::seconds(30)) { h.save_resume_data(); } } diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index c9ba53140..086f908d8 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -240,7 +240,7 @@ namespace libtorrent // of the piece. ``piece`` is the piece index that was read. ``size`` is the // number of bytes that was read. // - // If the operation fails, ec will indicat what went wrong. + // If the operation fails, ec will indicate what went wrong. struct TORRENT_EXPORT read_piece_alert TORRENT_FINAL : torrent_alert { // internal @@ -1469,11 +1469,11 @@ namespace libtorrent error_code error; #ifndef TORRENT_NO_DEPRECATE - // If the error happend to a specific file, ``file`` is the path to it. + // If the error happened to a specific file, ``file`` is the path to it. std::string file; #endif - // If the error happend to a specific file, this returns the path to it. + // If the error happened to a specific file, this returns the path to it. char const* file_path() const; // If the error happened in a disk operation. a NULL-terminated string of @@ -2226,7 +2226,7 @@ namespace libtorrent }; // holds statistics about a current dht_lookup operation. - // a DHT lookup is the travesal of nodes, looking up a + // a DHT lookup is the traversal of nodes, looking up a // set of target nodes in the DHT for retrieving and possibly // storing information in the DHT struct TORRENT_EXPORT dht_lookup diff --git a/include/libtorrent/bandwidth_limit.hpp b/include/libtorrent/bandwidth_limit.hpp index cc21d715b..3c7a3f8fe 100644 --- a/include/libtorrent/bandwidth_limit.hpp +++ b/include/libtorrent/bandwidth_limit.hpp @@ -33,9 +33,13 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_BANDWIDTH_CHANNEL_HPP_INCLUDED #define TORRENT_BANDWIDTH_CHANNEL_HPP_INCLUDED +#include "libtorrent/aux_/disable_warnings_push.hpp" + #include #include +#include "libtorrent/aux_/disable_warnings_pop.hpp" + #include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/include/libtorrent/disk_buffer_holder.hpp b/include/libtorrent/disk_buffer_holder.hpp index 0e7e3d94e..5130df8e2 100644 --- a/include/libtorrent/disk_buffer_holder.hpp +++ b/include/libtorrent/disk_buffer_holder.hpp @@ -64,11 +64,11 @@ namespace libtorrent // The disk buffer holder acts like a ``scoped_ptr`` that frees a disk buffer // when it's destructed, unless it's released. ``release`` returns the disk - // buffer and transferres ownership and responsibility to free it to the caller. + // buffer and transfers ownership and responsibility to free it to the caller. // // A disk buffer is freed by passing it to ``session_impl::free_disk_buffer()``. // - // ``buffer()`` returns the pointer without transferring responsibility. If + // ``get()`` returns the pointer without transferring responsibility. If // this buffer has been released, ``buffer()`` will return 0. struct TORRENT_EXPORT disk_buffer_holder { diff --git a/include/libtorrent/disk_io_thread.hpp b/include/libtorrent/disk_io_thread.hpp index 52822517c..8045e3c53 100644 --- a/include/libtorrent/disk_io_thread.hpp +++ b/include/libtorrent/disk_io_thread.hpp @@ -350,7 +350,7 @@ namespace libtorrent void clear_piece(piece_manager* storage, int index) TORRENT_OVERRIDE; // implements buffer_allocator_interface - void reclaim_block(block_cache_reference ref); + void reclaim_block(block_cache_reference ref) TORRENT_OVERRIDE; void free_disk_buffer(char* buf) TORRENT_OVERRIDE { m_disk_cache.free_buffer(buf); } char* allocate_disk_buffer(char const* category) TORRENT_OVERRIDE { @@ -375,7 +375,8 @@ namespace libtorrent block_cache* cache() { return &m_disk_cache; } #if TORRENT_USE_ASSERTS - bool is_disk_buffer(char* buffer) const { return m_disk_cache.is_disk_buffer(buffer); } + bool is_disk_buffer(char* buffer) const TORRENT_OVERRIDE + { return m_disk_cache.is_disk_buffer(buffer); } #endif enum thread_type_t { @@ -386,7 +387,7 @@ namespace libtorrent void thread_fun(int thread_id, thread_type_t type , boost::shared_ptr w); - file_pool& files() { return m_file_pool; } + virtual file_pool& files() TORRENT_OVERRIDE { return m_file_pool; } io_service& get_io_service() { return m_ios; } diff --git a/include/libtorrent/hasher.hpp b/include/libtorrent/hasher.hpp index 9bdbac22c..2e6a6a5eb 100644 --- a/include/libtorrent/hasher.hpp +++ b/include/libtorrent/hasher.hpp @@ -33,12 +33,16 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_HASHER_HPP_INCLUDED #define TORRENT_HASHER_HPP_INCLUDED -#include - #include "libtorrent/peer_id.hpp" #include "libtorrent/config.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/aux_/disable_warnings_push.hpp" + +#include + +#include "libtorrent/aux_/disable_warnings_pop.hpp" + #ifdef TORRENT_USE_GCRYPT #include diff --git a/include/libtorrent/heterogeneous_queue.hpp b/include/libtorrent/heterogeneous_queue.hpp index ffdf33181..bed8c2bee 100644 --- a/include/libtorrent/heterogeneous_queue.hpp +++ b/include/libtorrent/heterogeneous_queue.hpp @@ -163,9 +163,9 @@ namespace libtorrent { const static int header_size = (sizeof(header_t) + sizeof(uintptr_t) - 1) / sizeof(uintptr_t); - void grow_capacity(int size) + void grow_capacity(int const size) { - int amount_to_grow = (std::max)(size + header_size + int const amount_to_grow = (std::max)(size + header_size , (std::max)(m_capacity * 3 / 2, 128)); uintptr_t* new_storage = new uintptr_t[m_capacity + amount_to_grow]; diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp index b48c5e02c..c1049e234 100644 --- a/include/libtorrent/http_connection.hpp +++ b/include/libtorrent/http_connection.hpp @@ -207,7 +207,7 @@ private: // maximum size of bottled buffer int m_max_bottled_buffer_size; - + // the current download limit, in bytes per second // 0 is unlimited. int m_rate_limit; diff --git a/include/libtorrent/io.hpp b/include/libtorrent/io.hpp index 8d6aaa31b..83f9dc31f 100644 --- a/include/libtorrent/io.hpp +++ b/include/libtorrent/io.hpp @@ -33,7 +33,10 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_IO_HPP_INCLUDED #define TORRENT_IO_HPP_INCLUDED +#include "libtorrent/aux_/disable_warnings_push.hpp" #include +#include "libtorrent/aux_/disable_warnings_pop.hpp" + #include #include // for copy #include // for memcpy diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 626d527fd..5f726f2f4 100644 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -588,7 +588,7 @@ namespace libtorrent // recorded as piece_downloading_reverse, which really means the same // as piece_downloading, it just saves space to also indicate that it // has a bit lower priority. The reverse bit is only relevant if the - // state is piece_downloadin. + // state is piece_downloading. boost::uint32_t download_state : 3; // TODO: 2 having 8 priority levels is probably excessive. It should @@ -660,7 +660,7 @@ namespace libtorrent // +---+---+---+ // this '3' is called prio_factor // - // the manually set priority takes presedence over the availability + // the manually set priority takes precedence over the availability // by multiplying availability by priority. int priority(piece_picker const* picker) const @@ -774,7 +774,7 @@ namespace libtorrent mutable std::vector m_priority_boundries; // each piece that's currently being downloaded has an entry in this list - // with block allocations. i.e. it says wich parts of the piece that is + // with block allocations. i.e. it says which parts of the piece that is // being downloaded. This list is ordered by piece index to make lookups // efficient there are as many buckets as there are piece states. See // piece_pos::state_t. The only download state that does not have a diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index ccf82621b..524e5a7ef 100644 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -194,7 +194,7 @@ namespace libtorrent // // ``orig_files()`` returns the original (unmodified) file storage for // this torrent. This is used by the web server connection, which needs - // to request files with the original names. Filename may be chaged using + // to request files with the original names. Filename may be changed using // ``torrent_info::rename_file()``. // // For more information on the file_storage object, see the separate diff --git a/include/libtorrent/torrent_peer.hpp b/include/libtorrent/torrent_peer.hpp index d6edec89a..59f47da70 100644 --- a/include/libtorrent/torrent_peer.hpp +++ b/include/libtorrent/torrent_peer.hpp @@ -73,7 +73,7 @@ namespace libtorrent // this torrent_peer. i.e. These are only updated // when the connection is closed. For the // total amount of upload and download - // we'll have to add thes figures with the + // we'll have to add these figures with the // statistics from the peer_connection. // since these values don't need to be stored // with byte-precision, they specify the number @@ -115,7 +115,7 @@ namespace libtorrent // this torrent_peer has unsigned failcount:5; // [0, 31] - // incoming peers (that don't advertize their listen port) + // incoming peers (that don't advertise their listen port) // will not be considered connectable. Peers that // we have a listen port for will be assumed to be. bool connectable:1; @@ -188,7 +188,7 @@ namespace libtorrent bool supports_holepunch:1; // this is set to one for web seeds. Web seeds // are not stored in the policy m_peers list, - // and are excempt from connect candidate bookkeeping + // and are exempt from connect candidate bookkeeping // so, any torrent_peer with the web_seed bit set, is // never considered a connect candidate bool web_seed:1; diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index 6df86b00c..49cd84e77 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -150,6 +150,9 @@ namespace libtorrent boost::uint32_t key; int num_want; +#if TORRENT_USE_IPV6 + address_v6 ipv6; +#endif sha1_hash info_hash; peer_id pid; address bind_ip; diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index 1f27b4c2f..60ba212c5 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -113,25 +113,34 @@ namespace libtorrent template void get_option(SocketOption const& opt, error_code& ec) { - m_ipv4_sock.get_option(opt, ec); #if TORRENT_USE_IPV6 - m_ipv6_sock.get_option(opt, ec); + if (opt.level(udp::v6()) == IPPROTO_IPV6) + m_ipv6_sock.get_option(opt, ec); + else #endif + m_ipv4_sock.get_option(opt, ec); } template void set_option(SocketOption const& opt, error_code& ec) { - m_ipv4_sock.set_option(opt, ec); + if (opt.level(udp::v4()) != IPPROTO_IPV6) + m_ipv4_sock.set_option(opt, ec); #if TORRENT_USE_IPV6 - m_ipv6_sock.set_option(opt, ec); + if (opt.level(udp::v6()) != IPPROTO_IP) + m_ipv6_sock.set_option(opt, ec); #endif } template void get_option(SocketOption& opt, error_code& ec) { - m_ipv4_sock.get_option(opt, ec); +#if TORRENT_USE_IPV6 + if (opt.level(udp::v6()) == IPPROTO_IPV6) + m_ipv6_sock.get_option(opt, ec); + else +#endif + m_ipv4_sock.get_option(opt, ec); } udp::endpoint proxy_addr() const { return m_proxy_addr; } diff --git a/include/libtorrent/utp_stream.hpp b/include/libtorrent/utp_stream.hpp index 2728f77f5..ede524e2e 100644 --- a/include/libtorrent/utp_stream.hpp +++ b/include/libtorrent/utp_stream.hpp @@ -64,10 +64,10 @@ namespace libtorrent #endif #if TORRENT_UTP_LOG - bool is_utp_stream_logging(); + TORRENT_EXPORT bool is_utp_stream_logging(); // This function should be used at the very beginning and very end of your program. - void set_utp_stream_logging(bool enable); + TORRENT_EXPORT void set_utp_stream_logging(bool enable); #endif TORRENT_EXTRA_EXPORT bool compare_less_wrap(boost::uint32_t lhs @@ -90,8 +90,8 @@ namespace libtorrent }; // internal: the point of the bif_endian_int is two-fold - // one purpuse is to not have any alignment requirements - // so that any byffer received from the network can be cast + // one purpose is to not have any alignment requirements + // so that any buffer received from the network can be cast // to it and read as an integer of various sizes without // triggering a bus error. The other purpose is to convert // from network byte order to host byte order when read and diff --git a/simulation/libsimulator b/simulation/libsimulator index ce7d45687..0151d5c17 160000 --- a/simulation/libsimulator +++ b/simulation/libsimulator @@ -1 +1 @@ -Subproject commit ce7d45687bb10dac8f533cf359afc7c78de705f7 +Subproject commit 0151d5c17fa3f4cf0ce518d0b8f90a23792c9b24 diff --git a/simulation/test_tracker.cpp b/simulation/test_tracker.cpp index 8166765df..afa8ef6d5 100644 --- a/simulation/test_tracker.cpp +++ b/simulation/test_tracker.cpp @@ -39,6 +39,9 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/announce_entry.hpp" #include "libtorrent/session.hpp" +#include "libtorrent/create_torrent.hpp" +#include "libtorrent/file_storage.hpp" +#include "libtorrent/torrent_info.hpp" using namespace libtorrent; using namespace sim; @@ -397,7 +400,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 p.name = "test-torrent"; p.save_path = "."; p.info_hash.assign("abababababababababab"); - int const delay = setup(p); + int const delay = setup(p, *ses); ses->async_add_torrent(p); // run the test 5 seconds in @@ -434,7 +437,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2 template void tracker_test(Announce a, Test1 test1, Test2 test2, char const* url_path = "/announce") { - tracker_test([](lt::add_torrent_params& p) { + tracker_test([](lt::add_torrent_params& p, lt::session&) { p.trackers.push_back("http://tracker.com:8080/announce"); return 5; }, @@ -629,7 +632,7 @@ TORRENT_TEST(try_next) bool got_announce = false; tracker_test( - [](lt::add_torrent_params& p) + [](lt::add_torrent_params& p, lt::session&) { // TODO: 3 use tracker_tiers here to put the trackers in different tiers p.trackers.push_back("udp://failing-tracker.com/announce"); @@ -691,6 +694,113 @@ TORRENT_TEST(try_next) TEST_EQUAL(got_announce, true); } +boost::shared_ptr make_torrent(bool priv) +{ + file_storage fs; + fs.add_file("foobar", 13241); + create_torrent ct(fs); + + ct.add_tracker("http://tracker.com:8080/announce"); + + for (int i = 0; i < ct.num_pieces(); ++i) + ct.set_hash(i, sha1_hash(0)); + + ct.set_priv(priv); + + entry e = ct.generate(); + std::vector buf; + bencode(std::back_inserter(buf), e); + error_code ec; + return boost::make_shared(buf.data(), buf.size(), ec); +} + +// make sure we _do_ send our IPv6 address to trackers for private torrents +TORRENT_TEST(tracker_ipv6_argument) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, false); + ses.apply_settings(pack); + p.ti = make_torrent(true); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos != std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, true); +} + +// make sure we do _not_ send our IPv6 address to trackers for non-private +// torrents +TORRENT_TEST(tracker_ipv6_argument_non_private) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, false); + ses.apply_settings(pack); + p.ti = make_torrent(false); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos == std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, false); +} + +TORRENT_TEST(tracker_ipv6_argument_privacy_mode) +{ + bool got_announce = false; + bool got_ipv6 = false; + tracker_test( + [](lt::add_torrent_params& p, lt::session& ses) + { + settings_pack pack; + pack.set_bool(settings_pack::anonymous_mode, true); + ses.apply_settings(pack); + p.ti = make_torrent(true); + return 60; + }, + [&](std::string method, std::string req + , std::map& headers) + { + got_announce = true; + int pos = req.find("&ipv6="); + TEST_CHECK(pos == std::string::npos); + got_ipv6 = pos != std::string::npos; + return sim::send_response(200, "OK", 11) + "d5:peers0:e"; + } + , [](torrent_handle h) {} + , [](torrent_handle h) {}); + TEST_EQUAL(got_announce, true); + TEST_EQUAL(got_ipv6, false); +} + // TODO: test external IP // TODO: test with different queuing settings // TODO: test when a torrent transitions from downloading to finished and diff --git a/src/ConvertUTF.cpp b/src/ConvertUTF.cpp index c661118ea..2a4bb6992 100644 --- a/src/ConvertUTF.cpp +++ b/src/ConvertUTF.cpp @@ -1,8 +1,8 @@ /* * Copyright 2001-2004 Unicode, Inc. - * + * * Disclaimer - * + * * This source code is provided as is by Unicode, Inc. No claims are * made as to fitness for any particular purpose. No warranties of any * kind are expressed or implied. The recipient agrees to determine @@ -10,9 +10,9 @@ * purchased on magnetic or optical media from Unicode, Inc., the * sole remedy for any claim will be exchange of defective media * within 90 days of receipt. - * + * * Limitations on Rights to Redistribute This Code - * + * * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form @@ -26,10 +26,10 @@ Author: Mark E. Davis, 1994. Rev History: Rick McGowan, fixes & updates May 2001. Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. + mods suggested by S. Parent & A. Lillich. June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. July 2003: slight mods to back out aggressive FFFE detection. Jan 2004: updated switches in from-UTF8 conversions. Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. @@ -55,113 +55,111 @@ static const UTF32 halfMask = 0x3FFUL; #define UNI_SUR_HIGH_END (UTF32)0xDBFF #define UNI_SUR_LOW_START (UTF32)0xDC00 #define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { UTF32 ch; if (target >= targetEnd) { - result = targetExhausted; break; + result = targetExhausted; break; } ch = *source++; if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; } else { - *target++ = UNI_REPLACEMENT_CHAR; + *target++ = UNI_REPLACEMENT_CHAR; } - } else { + } else { *target++ = (UTF16)ch; /* normal case */ - } + } } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { + if (flags == strictConversion) { result = sourceIllegal; - } else { + } else { *target++ = UNI_REPLACEMENT_CHAR; - } + } } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { --source; /* Back up source pointer! */ result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } - } - *sourceStart = source; - *targetStart = target; - return result; + } + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF32* target = *targetStart; - UTF32 ch, ch2; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; + ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; } - } else { /* We don't have the 16 bits following the high surrogate. */ + } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; - } + } } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; - } + } } if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; } *target++ = ch; - } - *sourceStart = source; - *targetStart = target; + } + *sourceStart = source; + *targetStart = target; #ifdef CVTUTF_DEBUG if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); } #endif - return result; + return result; } /* --------------------------------------------------------------------- */ @@ -174,14 +172,14 @@ if (result == sourceIllegal) { * allowed in earlier algorithms. */ static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 }; /* @@ -189,8 +187,8 @@ static const char trailingBytesForUTF8[256] = { * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; /* * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed @@ -214,71 +212,71 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, + const UTF16** sourceStart, const UTF16* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; + const UTF32 byteMark = 0x80; const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ ch = *source++; /* If we have a surrogate pair, convert to UTF32 first. */ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { UTF32 ch2 = *source; /* If it's a low surrogate, convert to UTF32. */ if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; + ++source; } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; } - } else { /* We don't have the 16 bits following the high surrogate. */ + } else { /* We don't have the 16 bits following the high surrogate. */ --source; /* return to the high surrogate */ result = sourceExhausted; break; - } + } } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; - } + } } /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; } target += bytesToWrite; if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; + } + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ @@ -295,28 +293,28 @@ ConversionResult ConvertUTF16toUTF8 ( */ static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; } - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) return false; - return true; + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; } /* --------------------------------------------------------------------- */ @@ -326,216 +324,216 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) { * This is not used here; it's just exported. */ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { return false; - } - return isLegalUTF8(source, length); + } + return isLegalUTF8(source, length); } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; + result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; + result = sourceIllegal; + break; } /* * The cases all fall through. See "Note A" below. */ switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; } if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; } else { - *target++ = UNI_REPLACEMENT_CHAR; + *target++ = UNI_REPLACEMENT_CHAR; } - } else { + } else { *target++ = (UTF16)ch; /* normal case */ - } + } } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { + if (flags == strictConversion) { result = sourceIllegal; source -= (extraBytesToRead+1); /* return to the start */ break; /* Bail out; shouldn't continue */ - } else { + } else { *target++ = UNI_REPLACEMENT_CHAR; - } + } } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { source -= (extraBytesToRead+1); /* Back up source pointer! */ result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); } - } - *sourceStart = source; - *targetStart = target; - return result; + } + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, + const UTF32** sourceStart, const UTF32* sourceEnd, UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { UTF32 ch; unsigned short bytesToWrite = 0; const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; + const UTF32 byteMark = 0x80; ch = *source++; if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { --source; /* return to the illegal value itself */ result = sourceIllegal; break; - } + } } /* * Figure out how many bytes the result will require. Turn any * illegally large UTF32 things (> Plane 17) into replacement chars. */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; } - + target += bytesToWrite; if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; } switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); } target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; + } + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- */ ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, + const UTF8** sourceStart, const UTF8* sourceEnd, UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF32* target = *targetStart; - while (source < sourceEnd) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { UTF32 ch = 0; unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; + result = sourceExhausted; break; } /* Do this check whether lenient or strict */ if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; + result = sourceIllegal; + break; } /* - * The cases all fall through. See "Note A" below. - */ + * The cases all fall through. See "Note A" below. + */ switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; } ch -= offsetsFromUTF8[extraBytesToRead]; if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; } if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; } else { - *target++ = UNI_REPLACEMENT_CHAR; + *target++ = UNI_REPLACEMENT_CHAR; } - } else { + } else { *target++ = ch; - } + } } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; } - } - *sourceStart = source; - *targetStart = target; - return result; + } + *sourceStart = source; + *targetStart = target; + return result; } /* --------------------------------------------------------------------- - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: { - int tmpBytesToRead = extraBytesToRead+1; - do { + int tmpBytesToRead = extraBytesToRead+1; + do { ch += *source++; --tmpBytesToRead; if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); + } while (tmpBytesToRead > 0); } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. --------------------------------------------------------------------- */ diff --git a/src/Makefile.am b/src/Makefile.am index c34e0597c..c31f29fde 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -131,6 +131,7 @@ libtorrent_rasterbar_la_SOURCES = \ torrent_info.cpp \ torrent_peer.cpp \ torrent_peer_allocator.cpp \ + torrent_status.cpp \ time.cpp \ timestamp_history.cpp \ tracker_manager.cpp \ diff --git a/src/bandwidth_queue_entry.cpp b/src/bandwidth_queue_entry.cpp index 718de558f..5086bddfb 100644 --- a/src/bandwidth_queue_entry.cpp +++ b/src/bandwidth_queue_entry.cpp @@ -30,7 +30,12 @@ POSSIBILITY OF SUCH DAMAGE. */ +#include "libtorrent/aux_/disable_warnings_push.hpp" + #include + +#include "libtorrent/aux_/disable_warnings_pop.hpp" + #include "libtorrent/bandwidth_queue_entry.hpp" #include #include diff --git a/src/block_cache.cpp b/src/block_cache.cpp index 32e2a222d..652208cf3 100644 --- a/src/block_cache.cpp +++ b/src/block_cache.cpp @@ -1733,7 +1733,6 @@ void block_cache::check_invariant() const TORRENT_PIECE_ASSERT(!p.blocks[k].pending, &p); TORRENT_PIECE_ASSERT(p.blocks[k].refcount == 0, &p); } - TORRENT_PIECE_ASSERT(p.blocks[k].refcount >= 0, &p); num_refcount += p.blocks[k].refcount; } TORRENT_PIECE_ASSERT(num_blocks == p.num_blocks, &p); diff --git a/src/file.cpp b/src/file.cpp index 93f1e93f2..e49b453c8 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -468,7 +468,7 @@ namespace libtorrent if (::rename(f1.c_str(), f2.c_str()) < 0) #endif { - ec.assign(errno, system_category()); + ec.assign(errno, generic_category()); return; } } diff --git a/src/http_connection.cpp b/src/http_connection.cpp index bcf4f5521..8f2f9eb70 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -81,6 +81,8 @@ http_connection::http_connection(io_service& ios , m_connect_handler(ch) , m_filter_handler(fh) , m_timer(ios) + , m_read_timeout(seconds(5)) + , m_completion_timeout(seconds(5)) , m_limiter_timer(ios) , m_last_receive(aux::time_now()) , m_start_time(aux::time_now()) diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 89fd0be7a..4887462e8 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -183,20 +183,22 @@ namespace libtorrent { url += "&ip=" + escape_string(announce_ip.c_str(), announce_ip.size()); } -// TODO: support this somehow -/* else if (settings.get_bool(settings_pack::announce_double_nat) - && is_local(m_ses.listen_address())) - { - // only use the global external listen address here - // if it turned out to be on a local network - // since otherwise the tracker should use our - // source IP to determine our origin - url += "&ip=" + print_address(m_ses.listen_address()); - } -*/ } } +#if TORRENT_USE_IPV6 + if (tracker_req().ipv6 != address_v6() && !i2p) + { + error_code err; + std::string const ip = tracker_req().ipv6.to_string(err); + if (!err) + { + url += "&ipv6="; + url += ip; + } + } +#endif + m_tracker_connection.reset(new http_connection(get_io_service(), m_man.host_resolver() , boost::bind(&http_tracker_connection::on_response, shared_from_this(), _1, _2, _3, _4) , true, settings.get_int(settings_pack::max_http_recv_buffer_size) diff --git a/src/part_file.cpp b/src/part_file.cpp index 0ca5b3951..b6e51f340 100644 --- a/src/part_file.cpp +++ b/src/part_file.cpp @@ -301,8 +301,10 @@ namespace libtorrent void part_file::export_file(file& f, boost::int64_t offset, boost::int64_t size, error_code& ec) { + mutex::scoped_lock l(m_mutex); + int piece = offset / m_piece_size; - int end = ((offset + size) + m_piece_size - 1) / m_piece_size; + int const end = ((offset + size) + m_piece_size - 1) / m_piece_size; boost::scoped_array buf; @@ -311,30 +313,49 @@ namespace libtorrent for (; piece < end; ++piece) { boost::unordered_map::iterator i = m_piece_map.find(piece); - int block_to_copy = (std::min)(m_piece_size - piece_offset, size); + int const block_to_copy = (std::min)(m_piece_size - piece_offset, size); if (i != m_piece_map.end()) { + int const slot = i->second; open_file(file::read_only, ec); if (ec) return; if (!buf) buf.reset(new char[m_piece_size]); - boost::int64_t slot_offset = boost::int64_t(m_header_size) + boost::int64_t(i->second) * m_piece_size; - file::iovec_t v = { buf.get(), size_t(block_to_copy) }; + boost::int64_t const slot_offset = boost::int64_t(m_header_size) + + boost::int64_t(slot) * m_piece_size; + + // don't hold the lock during disk I/O + l.unlock(); + + file::iovec_t const v = { buf.get(), size_t(block_to_copy) }; int ret = m_file.readv(slot_offset + piece_offset, &v, 1, ec); TORRENT_ASSERT(ec || ret == block_to_copy); if (ec || ret != block_to_copy) return; - ret = f.writev(file_offset, &v, 1, ec); TORRENT_ASSERT(ec || ret == block_to_copy); if (ec || ret != block_to_copy) return; + // we're done with the disk I/O, grab the lock again to update + // the slot map + l.lock(); + if (block_to_copy == m_piece_size) { - m_free_slots.push_back(i->second); - m_piece_map.erase(i); - m_dirty_metadata = true; + // since we released the lock, it's technically possible that + // another thread removed this slot map entry, and invalidated + // our iterator. Now that we hold the lock again, perform + // another lookup to be sure. + boost::unordered_map::iterator j = m_piece_map.find(piece); + if (j != m_piece_map.end()) + { + // if the slot moved, that's really suspicious + TORRENT_ASSERT(j->second == slot); + m_free_slots.push_back(j->second); + m_piece_map.erase(j); + m_dirty_metadata = true; + } } } file_offset += block_to_copy; diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 02f4d101f..694553580 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -1893,21 +1893,15 @@ namespace libtorrent namespace { int append_blocks(std::vector& dst, std::vector& src - , int num_blocks) + , int const num_blocks) { if (src.empty()) return num_blocks; - int to_copy; -// if (prefer_contiguous_blocks == 0) - to_copy = (std::min)(int(src.size()), num_blocks); -// else -// to_copy = int(src.size()); + int const to_copy = (std::min)(int(src.size()), num_blocks); - dst.insert(dst.end() - , src.begin(), src.begin() + to_copy); - src.clear(); + dst.insert(dst.end(), src.begin(), src.begin() + to_copy); + src.erase(src.begin(), src.begin() + to_copy); return num_blocks - to_copy; } - } // lower availability comes first. This is a less-than comparison, it returns @@ -2338,8 +2332,7 @@ get_out: #endif ret |= picker_log_alert::backup1; - num_blocks = append_blocks(interesting_blocks, backup_blocks - , num_blocks); + num_blocks = append_blocks(interesting_blocks, backup_blocks, num_blocks); if (num_blocks <= 0) return ret; ret |= picker_log_alert::backup2; @@ -2390,7 +2383,7 @@ get_out: // we either don't have this piece, or we've already requested from it if (!pieces[dp.index]) continue; - // if we already have the piece, obviously we should not have + // if we already have the piece, obviously we should not have // since this is a partial piece in the piece_downloading state, we // should not already have it TORRENT_ASSERT(!m_piece_map[dp.index].have()); @@ -3333,7 +3326,6 @@ get_out: info.peer = peer; if (info.state == block_info::state_requested) --i->requested; - TORRENT_ASSERT(i->requested >= 0); if (info.state == block_info::state_writing || info.state == block_info::state_finished) return false; @@ -3493,7 +3485,6 @@ get_out: info.peer = peer; TORRENT_ASSERT(info.state == block_info::state_writing || peer == 0); - TORRENT_ASSERT(i->writing >= 0); if (info.state == block_info::state_writing) { --i->writing; diff --git a/src/resolve_links.cpp b/src/resolve_links.cpp index 9512f6e52..510998e3e 100644 --- a/src/resolve_links.cpp +++ b/src/resolve_links.cpp @@ -33,7 +33,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/resolve_links.hpp" #include "libtorrent/torrent_info.hpp" + +#include "libtorrent/aux_/disable_warnings_push.hpp" #include +#include "libtorrent/aux_/disable_warnings_pop.hpp" namespace libtorrent { diff --git a/src/storage.cpp b/src/storage.cpp index c6f272918..73b6e04b3 100644 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1017,9 +1017,13 @@ namespace libtorrent e.clear(); rename(old_path, new_path, e); // if the source file doesn't exist. That's not a problem + // we just ignore that file if (e == boost::system::errc::no_such_file_or_directory) e.clear(); + // on OSX, the error when trying to rename a file across different + // volumes is EXDEV, which will make it fall back to copying. + if (e) { if (flags == dont_replace && e == boost::system::errc::file_exists) @@ -1028,6 +1032,15 @@ namespace libtorrent continue; } + if (e == boost::system::errc::invalid_argument + || e == boost::system::errc::permission_denied) + { + ec.ec = e; + ec.file = i->second; + ec.operation = storage_error::rename; + break; + } + if (e != boost::system::errc::no_such_file_or_directory) { e.clear(); diff --git a/src/torrent.cpp b/src/torrent.cpp index f812678a1..46a839e93 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1079,8 +1079,6 @@ namespace libtorrent , resolve_filename(j->error.file).c_str()); #endif - TORRENT_ASSERT(j->piece >= 0); - if (j->action == disk_io_job::write) { piece_block block_finished(j->piece, j->d.io.offset / block_size()); @@ -2942,7 +2940,19 @@ namespace libtorrent if (req.downloaded < 0) req.downloaded = 0; req.event = e; - error_code ec; + +#if TORRENT_USE_IPV6 + // since sending our IPv6 address to the tracker may be sensitive. Only + // do that if we're not in anonymous mode and if it's a private torrent + if (!settings().get_bool(settings_pack::anonymous_mode) + && m_torrent_file + && m_torrent_file->priv()) + { + tcp::endpoint ep; + ep = m_ses.get_ipv6_interface(); + if (ep != tcp::endpoint()) req.ipv6 = ep.address().to_v6(); + } +#endif // if we are aborting. we don't want any new peers req.num_want = (req.event == tracker_request::stopped) @@ -5266,6 +5276,8 @@ namespace libtorrent TORRENT_ASSERT(num_have() >= m_picker->num_have_filtered()); } update_gauge(); + update_want_tick(); + if (filter_updated) { // we need to save this new state diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 2e32cc41d..ff0c1a976 100644 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -147,77 +147,6 @@ using libtorrent::aux::session_impl; namespace libtorrent { - torrent_status::torrent_status() - : error_file(torrent_status::error_file_none) - , total_download(0) - , total_upload(0) - , total_payload_download(0) - , total_payload_upload(0) - , total_failed_bytes(0) - , total_redundant_bytes(0) - , total_done(0) - , total_wanted_done(0) - , total_wanted(0) - , all_time_upload(0) - , all_time_download(0) - , added_time(0) - , completed_time(0) - , last_seen_complete(0) - , storage_mode(storage_mode_sparse) - , progress(0.f) - , progress_ppm(0) - , queue_position(0) - , download_rate(0) - , upload_rate(0) - , download_payload_rate(0) - , upload_payload_rate(0) - , num_seeds(0) - , num_peers(0) - , num_complete(-1) - , num_incomplete(-1) - , list_seeds(0) - , list_peers(0) - , connect_candidates(0) - , num_pieces(0) - , distributed_full_copies(0) - , distributed_fraction(0) - , distributed_copies(0.f) - , block_size(0) - , num_uploads(0) - , num_connections(0) - , uploads_limit(0) - , connections_limit(0) - , up_bandwidth_queue(0) - , down_bandwidth_queue(0) - , time_since_upload(0) - , time_since_download(0) - , active_time(0) - , finished_time(0) - , seeding_time(0) - , seed_rank(0) - , last_scrape(0) - , priority(0) - , state(checking_resume_data) - , need_save_resume(false) - , ip_filter_applies(true) - , upload_mode(false) - , share_mode(false) - , super_seeding(false) - , paused(false) - , auto_managed(false) - , sequential_download(false) - , is_seeding(false) - , is_finished(false) - , has_metadata(false) - , has_incoming(false) - , seed_mode(false) - , moving_storage(false) - , is_loaded(true) - , info_hash(0) - {} - - torrent_status::~torrent_status() {} - #ifndef BOOST_NO_EXCEPTIONS void throw_invalid_handle() { diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 594ad73ce..14034b1b5 100644 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -376,7 +376,6 @@ namespace libtorrent --added; TORRENT_ASSERT(added >= 0); } -#endif if (added == 0 && added_separator) { @@ -384,6 +383,7 @@ namespace libtorrent path.erase(path.end()-1); return; } +#endif if (path.empty()) path = "_"; } @@ -1346,7 +1346,7 @@ namespace libtorrent error_code ec; bdecode(m_info_section.get(), m_info_section.get() + m_info_section_size, m_info_dict, ec); - if (ec) return bdecode_node(); + if (ec) return bdecode_node(); } return m_info_dict.dict_find(key); } diff --git a/src/torrent_peer.cpp b/src/torrent_peer.cpp index 4c267e2dc..38278e2b3 100644 --- a/src/torrent_peer.cpp +++ b/src/torrent_peer.cpp @@ -159,7 +159,7 @@ namespace libtorrent , source(src) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) // assume no support in order to - // prefer opening non-encrypyed + // prefer opening non-encrypted // connections. If it fails, we'll // retry with encryption , pe_support(false) diff --git a/src/torrent_status.cpp b/src/torrent_status.cpp new file mode 100644 index 000000000..c04454b68 --- /dev/null +++ b/src/torrent_status.cpp @@ -0,0 +1,114 @@ +/* + +Copyright (c) 2015-2016, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "libtorrent/torrent_status.hpp" + +namespace libtorrent +{ + torrent_status::torrent_status() + : error_file(torrent_status::error_file_none) + , next_announce(seconds(0)) + , total_download(0) + , total_upload(0) + , total_payload_download(0) + , total_payload_upload(0) + , total_failed_bytes(0) + , total_redundant_bytes(0) + , total_done(0) + , total_wanted_done(0) + , total_wanted(0) + , all_time_upload(0) + , all_time_download(0) + , added_time(0) + , completed_time(0) + , last_seen_complete(0) + , storage_mode(storage_mode_sparse) + , progress(0.f) + , progress_ppm(0) + , queue_position(0) + , download_rate(0) + , upload_rate(0) + , download_payload_rate(0) + , upload_payload_rate(0) + , num_seeds(0) + , num_peers(0) + , num_complete(-1) + , num_incomplete(-1) + , list_seeds(0) + , list_peers(0) + , connect_candidates(0) + , num_pieces(0) + , distributed_full_copies(0) + , distributed_fraction(0) + , distributed_copies(0.f) + , block_size(0) + , num_uploads(0) + , num_connections(0) + , uploads_limit(0) + , connections_limit(0) + , up_bandwidth_queue(0) + , down_bandwidth_queue(0) + , time_since_upload(0) + , time_since_download(0) + , active_time(0) + , finished_time(0) + , seeding_time(0) + , seed_rank(0) + , last_scrape(0) + , priority(0) + , state(checking_resume_data) + , need_save_resume(false) + , ip_filter_applies(true) + , upload_mode(false) + , share_mode(false) + , super_seeding(false) + , paused(false) + , auto_managed(false) + , sequential_download(false) + , is_seeding(false) + , is_finished(false) + , has_metadata(false) + , has_incoming(false) + , seed_mode(false) + , moving_storage(false) + , is_loaded(true) + , announcing_to_trackers(false) + , announcing_to_lsd(false) + , announcing_to_dht(false) + , stop_when_ready(false) + , info_hash(0) + {} + + torrent_status::~torrent_status() {} + +} + diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 24532b2a3..5d28201dc 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -65,9 +65,7 @@ static struct utp_logger FILE* utp_log_file; mutex utp_log_mutex; - utp_logger() : utp_log_file(NULL) { - utp_log_file = fopen("utp.log", "w+"); - } + utp_logger() : utp_log_file(NULL) {} ~utp_logger() { if (utp_log_file) fclose(utp_log_file); @@ -504,7 +502,7 @@ public: // this is what we'll send back boost::uint32_t m_reply_micro; - // this is the advertized receive window the other end sent + // this is the advertised receive window the other end sent // we'll never have more un-acked bytes in flight // if this ever gets set to zero, we'll try one packet every // second until the window opens up again @@ -618,7 +616,7 @@ public: // this is a counter of how many times the current m_acked_seq_nr // has been ACKed. If it's ACKed more than 3 times, we assume the // packet with the next sequence number has been lost, and we trigger - // a re-send. Ovbiously an ACK only counts as a duplicate as long as + // a re-send. Obviously an ACK only counts as a duplicate as long as // we have outstanding packets following it. boost::uint8_t m_duplicate_acks; @@ -680,7 +678,7 @@ public: // this is true while the socket is in slow start mode. It's // only in slow-start during the start-up phase. Slow start // (contrary to what its name suggest) means that we're growing - // the congestion window (cwnd) exponetially rather than linearly. + // the congestion window (cwnd) exponentially rather than linearly. // this is done at startup of a socket in order to find its // link capacity faster. This behaves similar to TCP slow start bool m_slow_start:1; diff --git a/test/test_storage.cpp b/test/test_storage.cpp index 20206769f..0d6d83315 100644 --- a/test/test_storage.cpp +++ b/test/test_storage.cpp @@ -124,11 +124,11 @@ boost::shared_ptr setup_torrent(file_storage& fs , std::string const& test_path , aux::session_settings& set) { - fs.add_file("temp_storage/test1.tmp", 8); - fs.add_file("temp_storage/folder1/test2.tmp", 8); - fs.add_file("temp_storage/folder2/test3.tmp", 0); - fs.add_file("temp_storage/_folder3/test4.tmp", 0); - fs.add_file("temp_storage/_folder3/subfolder/test5.tmp", 8); + fs.add_file(combine_path("temp_storage", "test1.tmp"), 8); + fs.add_file(combine_path("temp_storage", combine_path("folder1", "test2.tmp")), 8); + fs.add_file(combine_path("temp_storage", combine_path("folder2", "test3.tmp")), 0); + fs.add_file(combine_path("temp_storage", combine_path("_folder3", "test4.tmp")), 0); + fs.add_file(combine_path("temp_storage", combine_path("_folder3", combine_path("subfolder", "test5.tmp"))), 8); libtorrent::create_torrent t(fs, 4, -1, 0); char buf_[4] = {0, 0, 0, 0}; @@ -1263,3 +1263,29 @@ TORRENT_TEST(readwritev_zero_size_files) TEST_CHECK(check_pattern(buf, 0)); } +TORRENT_TEST(move_storage_into_self) +{ + aux::session_settings set; + file_storage fs; + std::vector buf; + file_pool fp; + io_service ios; + disk_buffer_pool dp(16 * 1024, ios, boost::bind(&nop)); + boost::shared_ptr s = setup_torrent(fs, fp, buf + , current_working_directory() + , set); + + file::iovec_t b = {&buf[0], 4}; + storage_error se; + s->writev(&b, 1, 2, 0, 0, se); + + s->move_storage(combine_path("temp_storage", "folder1"), 0, se); + + printf("move error: %s\n", se.ec.message().c_str()); +#ifdef _WIN32 + TEST_EQUAL(se.ec, boost::system::errc::permission_denied); +#else + TEST_EQUAL(se.ec, boost::system::errc::invalid_argument); +#endif +} +