merged RC_1_1 into master

This commit is contained in:
arvidn 2017-01-21 02:28:29 -05:00
commit 173951ec7f
18 changed files with 195 additions and 89 deletions

View File

@ -50,6 +50,11 @@
* resume data no longer has timestamps of files
* require C++11 to build libtorrent
* storage optimization to peer classes
* fix torrent name in alerts of builds with deprecated functions
* make torrent_info::is_valid() return false if torrent failed to load
* fix per-torrent rate limits for >256 peer classes
* don't load user_agent and peer_fingerprint from session_state
* fix file rename issue with name prefix matching torrent name
* fix division by zero when setting tick_interval > 1000
* fix move_storage() to its own directory (would delete the files)

View File

@ -10,6 +10,8 @@ void bind_fingerprint()
using namespace boost::python;
using namespace libtorrent;
def("generate_fingerprint", &generate_fingerprint);
#ifndef TORRENT_NO_DEPRECATE
#ifdef __GNUC__
#pragma GCC diagnostic push

View File

@ -297,6 +297,9 @@ class test_session(unittest.TestCase):
self.assertEqual(s.get_settings()['num_want'], 66)
self.assertEqual(s.get_settings()['user_agent'], 'test123')
def test_fingerprint(self):
self.assertEqual(lt.generate_fingerprint('LT', 0, 1, 2, 3), '-LT0123-')
self.assertEqual(lt.generate_fingerprint('..', 10, 1, 2, 3), '-..A123-')
if __name__ == '__main__':
print(lt.__version__)

View File

@ -164,11 +164,6 @@ namespace libtorrent
return bind_ep.address();
}
// TODO: function not used and not exported in release?
// returns true if the given device exists
TORRENT_EXTRA_EXPORT bool has_interface(char const* name, io_service& ios
, error_code& ec);
// returns the device name whose local address is ``addr``. If
// no such device is found, an empty string is returned.
TORRENT_EXTRA_EXPORT std::string device_for_address(address addr

View File

@ -37,13 +37,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/assert.hpp"
#include <vector>
#include <deque>
#include <string>
#include <cstdint>
#include <memory>
namespace libtorrent
{
typedef std::uint16_t peer_class_t;
typedef std::uint32_t peer_class_t;
struct peer_class_info
{
@ -82,12 +83,13 @@ namespace libtorrent
int download_priority;
};
struct TORRENT_EXTRA_EXPORT peer_class : std::enable_shared_from_this<peer_class>
struct TORRENT_EXTRA_EXPORT peer_class
{
friend struct peer_class_pool;
explicit peer_class(std::string const& l)
: ignore_unchoke_slots(false)
: in_use(true)
, ignore_unchoke_slots(false)
, connection_limit_factor(100)
, label(l)
, references(1)
@ -96,6 +98,12 @@ namespace libtorrent
priority[1] = 1;
}
void clear()
{
in_use = false;
label.clear();
}
void set_info(peer_class_info const* pci);
void get_info(peer_class_info* pci) const;
@ -106,6 +114,9 @@ namespace libtorrent
// keeps track of the current quotas
bandwidth_channel channel[2];
// this is set to false when this slot is not in use for a peer_class
bool in_use;
bool ignore_unchoke_slots;
int connection_limit_factor;
@ -119,7 +130,6 @@ namespace libtorrent
private:
int references;
};
struct TORRENT_EXTRA_EXPORT peer_class_pool
@ -134,7 +144,7 @@ namespace libtorrent
// state for peer classes (a peer can belong to multiple classes)
// this can control
std::vector<std::shared_ptr<peer_class>> m_peer_classes;
std::deque<peer_class> m_peer_classes;
// indices in m_peer_classes that are no longer used
std::vector<peer_class_t> m_free_list;

View File

@ -128,6 +128,11 @@ namespace libtorrent
// The ``flags`` argument is used to filter which parts of the session
// state to save or load. By default, all state is saved/restored (except
// for the individual torrents). see save_state_flags_t
//
// When saving settings, there are two fields that are *not* loaded.
// ``peer_fingerprint`` and ``user_agent``. Those are left as configured
// by the ``session_settings`` passed to the session constructor or
// subsequently set via apply_settings().
void save_state(entry& e, std::uint32_t flags = 0xffffffff) const;
void load_state(bdecode_node const& e, std::uint32_t flags = 0xffffffff);

View File

@ -87,8 +87,13 @@ namespace libtorrent
void set_int(int name, int val);
void set_bool(int name, bool val);
bool has_val(int name) const;
// clear the settings pack from all settings
void clear();
// clear a specific setting from the pack
void clear(int name);
std::string const& get_str(int name) const;
int get_int(int name) const;
bool get_bool(int name) const;

View File

@ -77,17 +77,13 @@ namespace libtorrent {
}
#ifndef TORRENT_NO_DEPRECATE
name = torrent_name();
name = m_alloc.get().ptr(m_name_idx);
#endif
}
char const* torrent_alert::torrent_name() const
{
#ifndef TORRENT_NO_DEPRECATE
return name.c_str();
#else
return m_alloc.get().ptr(m_name_idx);
#endif
}
std::string torrent_alert::message() const
@ -125,11 +121,7 @@ namespace libtorrent {
char const* tracker_alert::tracker_url() const
{
#ifndef TORRENT_NO_DEPRECATE
return url.c_str();
#else
return m_alloc.get().ptr(m_url_idx);
#endif
}
std::string tracker_alert::message() const
@ -201,11 +193,7 @@ namespace libtorrent {
char const* file_renamed_alert::new_name() const
{
#ifndef TORRENT_NO_DEPRECATE
return name.c_str();
#else
return m_alloc.get().ptr(m_name_idx);
#endif
}
std::string file_renamed_alert::message() const
@ -299,11 +287,7 @@ namespace libtorrent {
char const* tracker_error_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.get().ptr(m_msg_idx);
#endif
}
std::string tracker_error_alert::message() const
@ -329,11 +313,7 @@ namespace libtorrent {
char const* tracker_warning_alert::warning_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.get().ptr(m_msg_idx);
#endif
}
std::string tracker_warning_alert::message() const
@ -384,12 +364,8 @@ namespace libtorrent {
char const* scrape_failed_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
if (m_msg_idx == aux::allocation_slot()) return "";
else return m_alloc.get().ptr(m_msg_idx);
#endif
}
std::string scrape_failed_alert::message() const
@ -655,11 +631,7 @@ namespace libtorrent {
char const* storage_moved_alert::storage_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return path.c_str();
#else
return m_alloc.get().ptr(m_path_idx);
#endif
}
storage_moved_failed_alert::storage_moved_failed_alert(
@ -676,11 +648,7 @@ namespace libtorrent {
char const* storage_moved_failed_alert::file_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return file.c_str();
#else
return m_alloc.get().ptr(m_file_idx);
#endif
}
std::string storage_moved_failed_alert::message() const
@ -1032,11 +1000,7 @@ namespace libtorrent {
char const* portmap_log_alert::log_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.get().ptr(m_log_idx);
#endif
}
std::string portmap_log_alert::message() const
@ -1075,11 +1039,7 @@ namespace libtorrent {
char const* fastresume_rejected_alert::file_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return file.c_str();
#else
return m_alloc.get().ptr(m_path_idx);
#endif
}
peer_blocked_alert::peer_blocked_alert(aux::stack_allocator& alloc
@ -1246,11 +1206,7 @@ namespace libtorrent {
char const* trackerid_alert::tracker_id() const
{
#ifndef TORRENT_NO_DEPRECATE
return trackerid.c_str();
#else
return m_alloc.get().ptr(m_tracker_idx);
#endif
}
std::string trackerid_alert::message() const
@ -1837,12 +1793,8 @@ namespace libtorrent {
char const* url_seed_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
if (m_msg_idx == aux::allocation_slot()) return "";
return m_alloc.get().ptr(m_msg_idx);
#endif
}
file_error_alert::file_error_alert(aux::stack_allocator& alloc

View File

@ -380,6 +380,7 @@ namespace libtorrent
TORRENT_ASSERT(ti.num_files() > 0);
TORRENT_ASSERT(ti.total_size() > 0);
if (!ti.is_valid()) return;
if (ti.creation_date() > 0) m_creation_date = ti.creation_date();
if (!ti.creator().empty()) set_creator(ti.creator().c_str());

View File

@ -1107,17 +1107,6 @@ namespace libtorrent
return ret;
}
// returns true if the given device exists
bool has_interface(char const* name, io_service& ios, error_code& ec)
{
std::vector<ip_interface> ifs = enum_net_interfaces(ios, ec);
if (ec) return false;
for (auto const& iface : ifs)
if (iface.name == name) return true;
return false;
}
// returns the device name whose local address is ``addr``. If
// no such device is found, an empty string is returned.
std::string device_for_address(address addr, io_service& ios, error_code& ec)

View File

@ -80,47 +80,47 @@ namespace libtorrent
{
ret = m_free_list.back();
m_free_list.pop_back();
m_peer_classes[ret] = peer_class(label);
}
else
{
TORRENT_ASSERT(m_peer_classes.size() < 0x10000);
TORRENT_ASSERT(m_peer_classes.size() < 0x100000000);
ret = peer_class_t(m_peer_classes.size());
m_peer_classes.push_back(std::shared_ptr<peer_class>());
m_peer_classes.push_back(peer_class(label));
}
TORRENT_ASSERT(m_peer_classes[ret].get() == nullptr);
m_peer_classes[ret] = std::make_shared<peer_class>(label);
return ret;
}
void peer_class_pool::decref(peer_class_t c)
{
TORRENT_ASSERT(c < m_peer_classes.size());
TORRENT_ASSERT(m_peer_classes[c].get());
TORRENT_ASSERT(m_peer_classes[c].in_use);
TORRENT_ASSERT(m_peer_classes[c].references > 0);
--m_peer_classes[c]->references;
if (m_peer_classes[c]->references) return;
m_peer_classes[c].reset();
--m_peer_classes[c].references;
if (m_peer_classes[c].references) return;
m_peer_classes[c].clear();
m_free_list.push_back(c);
}
void peer_class_pool::incref(peer_class_t c)
{
TORRENT_ASSERT(c < m_peer_classes.size());
TORRENT_ASSERT(m_peer_classes[c].get());
TORRENT_ASSERT(m_peer_classes[c].in_use);
++m_peer_classes[c]->references;
++m_peer_classes[c].references;
}
peer_class* peer_class_pool::at(peer_class_t c)
{
if (c >= m_peer_classes.size()) return nullptr;
return m_peer_classes[c].get();
if (c >= m_peer_classes.size() || !m_peer_classes[c].in_use) return nullptr;
return &m_peer_classes[c];
}
peer_class const* peer_class_pool::at(peer_class_t c) const
{
if (c >= m_peer_classes.size()) return nullptr;
return m_peer_classes[c].get();
if (c >= m_peer_classes.size() || !m_peer_classes[c].in_use) return nullptr;
return &m_peer_classes[c];
}
}

View File

@ -790,6 +790,12 @@ namespace aux {
{
// apply_settings_pack will update dht and proxy
settings_pack pack = load_pack_from_dict(settings);
// these settings are not loaded from state
// they are set by the client software, not configured by users
pack.clear(settings_pack::user_agent);
pack.clear(settings_pack::peer_fingerprint);
apply_settings_pack_impl(pack);
#ifndef TORRENT_DISABLE_DHT
need_update_dht = false;

View File

@ -666,4 +666,38 @@ namespace libtorrent
m_ints.clear();
m_bools.clear();
}
void settings_pack::clear(int const name)
{
switch (name & type_mask)
{
case string_type_base:
{
std::pair<boost::uint16_t, std::string> v(name, std::string());
std::vector<std::pair<boost::uint16_t, std::string> >::iterator i
= std::lower_bound(m_strings.begin(), m_strings.end(), v
, &compare_first<std::string>);
if (i != m_strings.end() && i->first == name) m_strings.erase(i);
break;
}
case int_type_base:
{
std::pair<boost::uint16_t, int> v(name, 0);
std::vector<std::pair<boost::uint16_t, int> >::iterator i
= std::lower_bound(m_ints.begin(), m_ints.end(), v
, &compare_first<int>);
if (i != m_ints.end() && i->first == name) m_ints.erase(i);
break;
}
case bool_type_base:
{
std::pair<boost::uint16_t, bool> v(name, false);
std::vector<std::pair<boost::uint16_t, bool> >::iterator i
= std::lower_bound(m_bools.begin(), m_bools.end(), v
, &compare_first<bool>);
if (i != m_bools.end() && i->first == name) m_bools.erase(i);
break;
}
}
}
}

View File

@ -1081,6 +1081,8 @@ namespace libtorrent
if (!name_ent)
{
ec = errors::torrent_missing_name;
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
@ -1097,14 +1099,22 @@ namespace libtorrent
// this is the counter used to name pad files
int pad_file_cnt = 0;
if (!extract_single_file(info, files, "", info_ptr_diff, true, pad_file_cnt, ec))
{
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
m_flags &= ~multifile;
}
else
{
if (!extract_files(files_node, files, name, info_ptr_diff, ec))
{
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
m_flags |= multifile;
}
TORRENT_ASSERT(!files.name().empty());
@ -1121,6 +1131,8 @@ namespace libtorrent
if (!pieces && !root_hash)
{
ec = errors::torrent_missing_pieces;
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
@ -1129,6 +1141,8 @@ namespace libtorrent
if (pieces.string_length() != files.num_pieces() * 20)
{
ec = errors::torrent_invalid_hashes;
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
@ -1142,11 +1156,15 @@ namespace libtorrent
if (root_hash.string_length() != 20)
{
ec = errors::torrent_invalid_hashes;
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
if (files.num_pieces() >= std::numeric_limits<int>::max()/2)
{
ec = errors::too_many_pieces_in_torrent;
// mark the torrent as invalid
m_files.set_piece_length(0);
return false;
}
int const num_leafs = merkle_num_leafs(files.num_pieces());

View File

@ -66,11 +66,11 @@ TORRENT_TEST(peer_class)
TEST_CHECK(id3 == id2 + 1);
// make sure refcounting works
TEST_CHECK(class_name(id3, pool) == "test3");
TEST_EQUAL(class_name(id3, pool), "test3");
pool.incref(id3);
TEST_CHECK(class_name(id3, pool) == "test3");
TEST_EQUAL(class_name(id3, pool), "test3");
pool.decref(id3);
TEST_CHECK(class_name(id3, pool) == "test3");
TEST_EQUAL(class_name(id3, pool), "test3");
pool.decref(id3);
// it should have been deleted now
TEST_CHECK(pool.at(id3) == nullptr);
@ -81,8 +81,8 @@ TORRENT_TEST(peer_class)
peer_class_info i;
pool.at(id2)->get_info(&i);
TEST_CHECK(i.upload_limit == 1000);
TEST_CHECK(i.download_limit == 2000);
TEST_EQUAL(i.upload_limit, 1000);
TEST_EQUAL(i.download_limit, 2000);
// test peer_class_type_filter
peer_class_type_filter filter;

View File

@ -304,3 +304,47 @@ TORRENT_TEST(session_shutdown)
lt::session ses(pack);
}
// make sure we don't restore peer_id from session state
TORRENT_TEST(save_state_peer_id)
{
lt::settings_pack pack;
pack.set_str(settings_pack::peer_fingerprint, "AAA");
lt::session ses(pack);
lt::peer_id const pid1 = ses.id();
TEST_CHECK(pid1[0] == 'A');
TEST_CHECK(pid1[1] == 'A');
TEST_CHECK(pid1[2] == 'A');
lt::entry st;
ses.save_state(st);
pack.set_str(settings_pack::peer_fingerprint, "foobar");
ses.apply_settings(pack);
lt::peer_id const pid2 = ses.id();
TEST_CHECK(pid2[0] == 'f');
TEST_CHECK(pid2[1] == 'o');
TEST_CHECK(pid2[2] == 'o');
TEST_CHECK(pid2[3] == 'b');
TEST_CHECK(pid2[4] == 'a');
TEST_CHECK(pid2[5] == 'r');
std::vector<char> buf;
bencode(std::back_inserter(buf), st);
bdecode_node state;
error_code ec;
int ret = bdecode(buf.data(), buf.data() + buf.size()
, state, ec, nullptr, 100, 1000);
TEST_EQUAL(ret, 0);
ses.load_state(state);
lt::peer_id const pid3 = ses.id();
TEST_CHECK(pid3[0] == 'f');
TEST_CHECK(pid3[1] == 'o');
TEST_CHECK(pid3[2] == 'o');
TEST_CHECK(pid3[3] == 'b');
TEST_CHECK(pid3[4] == 'a');
TEST_CHECK(pid3[5] == 'r');
}

View File

@ -132,6 +132,42 @@ TORRENT_TEST(clear)
TEST_EQUAL(pack.has_val(settings_pack::user_agent), false);
}
TORRENT_TEST(clear_single_int)
{
settings_pack sp;
sp.set_int(settings_pack::max_out_request_queue, 1337);
TEST_EQUAL(sp.get_int(settings_pack::max_out_request_queue), 1337);
sp.clear(settings_pack::max_out_request_queue);
TEST_EQUAL(sp.get_int(settings_pack::max_out_request_queue), 0);
}
TORRENT_TEST(clear_single_bool)
{
settings_pack sp;
sp.set_bool(settings_pack::send_redundant_have, true);
TEST_EQUAL(sp.get_bool(settings_pack::send_redundant_have), true);
sp.clear(settings_pack::send_redundant_have);
TEST_EQUAL(sp.get_bool(settings_pack::send_redundant_have), false);
}
TORRENT_TEST(clear_single_string)
{
settings_pack sp;
sp.set_str(settings_pack::user_agent, "foobar");
TEST_EQUAL(sp.get_str(settings_pack::user_agent), "foobar");
sp.clear(settings_pack::user_agent);
TEST_EQUAL(sp.get_str(settings_pack::user_agent), std::string());
}
TORRENT_TEST(duplicates)
{
settings_pack p;

View File

@ -762,6 +762,7 @@ TORRENT_TEST(parse_torrents)
std::printf("E: \"%s\"\nexpected: \"%s\"\n", ec.message().c_str()
, test_error_torrents[i].error.message().c_str());
TEST_CHECK(ec.message() == test_error_torrents[i].error.message());
TEST_EQUAL(ti->is_valid(), false);
}
}