merged changes from RC_1_0

This commit is contained in:
Arvid Norberg 2014-09-12 22:38:07 +00:00
parent acdcf4c888
commit eb32b1fef1
13 changed files with 264 additions and 46 deletions

View File

@ -27,6 +27,8 @@
* almost completely changed the storage interface (for custom storage) * almost completely changed the storage interface (for custom storage)
* added support for hashing pieces in multiple threads * added support for hashing pieces in multiple threads
1.0.2 release
* added missing force_proxy to python binding * added missing force_proxy to python binding
* anonymous_mode defaults to false * anonymous_mode defaults to false
* make DHT DOS detection more forgiving to bursts * make DHT DOS detection more forgiving to bursts
@ -103,6 +105,9 @@
* fix uTP edge case where udp socket buffer fills up * fix uTP edge case where udp socket buffer fills up
* fix nagle implementation in uTP * fix nagle implementation in uTP
0.16.18 release
* fix python3 support
* fix bug in lt_donthave extension * fix bug in lt_donthave extension
* expose i2p_alert to python. cleaning up of i2p connection code * expose i2p_alert to python. cleaning up of i2p connection code
* fixed overflow and download performance issue when downloading at high rates * fixed overflow and download performance issue when downloading at high rates

View File

@ -4,6 +4,19 @@
#include <libtorrent/sha1_hash.hpp> #include <libtorrent/sha1_hash.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include "bytes.hpp"
long get_hash(boost::python::object o)
{
using namespace boost::python;
return PyObject_Hash(str(o).ptr());
}
using namespace libtorrent;
bytes sha1_hash_bytes(const sha1_hash& bn) {
return bytes(bn.to_string());
}
void bind_sha1_hash() void bind_sha1_hash()
{ {
@ -19,7 +32,8 @@ void bind_sha1_hash()
.def("clear", &sha1_hash::clear) .def("clear", &sha1_hash::clear)
.def("is_all_zeros", &sha1_hash::is_all_zeros) .def("is_all_zeros", &sha1_hash::is_all_zeros)
.def("to_string", &sha1_hash::to_string) .def("to_string", &sha1_hash::to_string)
// .def("__getitem__", &sha1_hash::opreator[]) .def("__hash__", get_hash)
.def("to_bytes", sha1_hash_bytes)
; ;
scope().attr("big_number") = scope().attr("sha1_hash"); scope().attr("big_number") = scope().attr("sha1_hash");

View File

@ -0,0 +1,18 @@
// Copyright Arvid Norberg 2006-2013. 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 BYTES_HPP
#define BYTES_HPP
#include <string>
struct bytes
{
bytes(std::string const& s): arr(s) {}
bytes() {}
std::string arr;
};
#endif

View File

@ -6,20 +6,21 @@
#include <libtorrent/create_torrent.hpp> #include <libtorrent/create_torrent.hpp>
#include <libtorrent/file_storage.hpp> #include <libtorrent/file_storage.hpp>
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "bytes.hpp"
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
namespace namespace
{ {
void set_hash(create_torrent& c, int p, char const* hash) void set_hash(create_torrent& c, int p, bytes const& b)
{ {
c.set_hash(p, sha1_hash(hash)); c.set_hash(p, sha1_hash(b.arr));
} }
void set_file_hash(create_torrent& c, int f, char const* hash) void set_file_hash(create_torrent& c, int f, bytes const& b)
{ {
c.set_file_hash(f, sha1_hash(hash)); c.set_file_hash(f, sha1_hash(b.arr));
} }
void call_python_object(boost::python::object const& obj, int i) void call_python_object(boost::python::object const& obj, int i)

View File

@ -4,6 +4,7 @@
#include <boost/python.hpp> #include <boost/python.hpp>
#include <libtorrent/session.hpp> #include <libtorrent/session.hpp>
#include "bytes.hpp"
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
@ -27,7 +28,7 @@ struct entry_to_python
dict result; dict result;
for (entry::dictionary_type::const_iterator i(d.begin()), e(d.end()); i != e; ++i) for (entry::dictionary_type::const_iterator i(d.begin()), e(d.end()); i != e; ++i)
result[i->first] = i->second; result[bytes(i->first)] = i->second;
return result; return result;
} }
@ -39,7 +40,7 @@ struct entry_to_python
case entry::int_t: case entry::int_t:
return object(e.integer()); return object(e.integer());
case entry::string_t: case entry::string_t:
return object(e.string()); return object(bytes(e.string()));
case entry::list_t: case entry::list_t:
return convert(e.list()); return convert(e.list());
case entry::dictionary_t: case entry::dictionary_t:
@ -87,12 +88,24 @@ struct entry_from_python
for (std::size_t i = 0; i < length; ++i) for (std::size_t i = 0; i < length; ++i)
{ {
result.dict().insert( if (extract<bytes>(items[i][0]).check())
std::make_pair( {
extract<char const*>(items[i][0])() result.dict().insert(
, construct0(items[i][1]) std::make_pair(
) extract<bytes>(items[i][0])().arr,
); construct0(items[i][1])
)
);
}
else
{
result.dict().insert(
std::make_pair(
extract<char const*>(items[i][0])(),
construct0(items[i][1])
)
);
}
} }
return result; return result;
@ -111,9 +124,13 @@ struct entry_from_python
return result; return result;
} }
else if (extract<bytes>(e).check())
{
return entry(extract<bytes>(e)().arr);
}
else if (extract<str>(e).check()) else if (extract<str>(e).check())
{ {
return entry(extract<std::string>(e)()); return entry(extract<std::string>(e)());
} }
else if (extract<entry::integer_type>(e).check()) else if (extract<entry::integer_type>(e).check())
{ {

View File

@ -23,6 +23,7 @@
#include <libtorrent/extensions/ut_pex.hpp> #include <libtorrent/extensions/ut_pex.hpp>
#include "gil.hpp" #include "gil.hpp"
#include "bytes.hpp"
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
@ -171,7 +172,7 @@ namespace
p.ti = extract<boost::shared_ptr<torrent_info> >(params["ti"]); p.ti = extract<boost::shared_ptr<torrent_info> >(params["ti"]);
if (params.has_key("info_hash")) if (params.has_key("info_hash"))
p.info_hash = extract<sha1_hash>(params["info_hash"]); p.info_hash = sha1_hash(bytes(extract<bytes>(params["info_hash"])).arr);
if (params.has_key("name")) if (params.has_key("name"))
p.name = extract<std::string>(params["name"]); p.name = extract<std::string>(params["name"]);
p.save_path = extract<std::string>(params["save_path"]); p.save_path = extract<std::string>(params["save_path"]);

View File

@ -7,6 +7,7 @@
#include <libtorrent/torrent_info.hpp> #include <libtorrent/torrent_info.hpp>
#include "libtorrent/session_settings.hpp" #include "libtorrent/session_settings.hpp"
#include "libtorrent/time.hpp" #include "libtorrent/time.hpp"
#include "bytes.hpp"
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
@ -73,7 +74,7 @@ namespace
for (std::vector<sha1_hash>::const_iterator i = mt.begin() for (std::vector<sha1_hash>::const_iterator i = mt.begin()
, end(mt.end()); i != end; ++i) , end(mt.end()); i != end; ++i)
{ {
ret.append(i->to_string()); ret.append(bytes(i->to_string()));
} }
return ret; return ret;
} }
@ -82,7 +83,7 @@ namespace
{ {
std::vector<sha1_hash> h; std::vector<sha1_hash> h;
for (int i = 0, e = len(hashes); i < e; ++i) for (int i = 0, e = len(hashes); i < e; ++i)
h.push_back(sha1_hash(extract<char const*>(hashes[i]))); h.push_back(sha1_hash(bytes(extract<bytes>(hashes[i])).arr));
ti.set_merkle_tree(h); ti.set_merkle_tree(h);
} }

View File

@ -5,30 +5,84 @@
#include <libtorrent/identify_client.hpp> #include <libtorrent/identify_client.hpp>
#include <libtorrent/bencode.hpp> #include <libtorrent/bencode.hpp>
#include <boost/python.hpp> #include <boost/python.hpp>
#include "bytes.hpp"
using namespace boost::python; using namespace boost::python;
using namespace libtorrent; using namespace libtorrent;
struct bytes_to_python
{
static PyObject* convert(bytes const& p)
{
#if PY_MAJOR_VERSION >= 3
PyObject *ret = PyBytes_FromStringAndSize(p.arr.c_str(), p.arr.size());
#else
PyObject *ret = PyString_FromStringAndSize(p.arr.c_str(), p.arr.size());
#endif
return ret;
}
};
struct bytes_from_python
{
bytes_from_python()
{
converter::registry::push_back(
&convertible, &construct, type_id<bytes>());
}
static void* convertible(PyObject* x)
{
#if PY_MAJOR_VERSION >= 3
return PyBytes_Check(x) ? x : NULL;
#else
return PyString_Check(x) ? x : NULL;
#endif
}
static void construct(PyObject* x, converter::rvalue_from_python_stage1_data* data)
{
#if PY_MAJOR_VERSION >= 3
void* storage = ((converter::rvalue_from_python_storage<bytes>*)data)->storage.bytes;
bytes* ret = new (storage) bytes();
ret->arr.resize(PyBytes_Size(x));
memcpy(&ret->arr[0], PyBytes_AsString(x), ret->arr.size());
data->convertible = storage;
#else
void* storage = ((converter::rvalue_from_python_storage<bytes>*)data)->storage.bytes;
bytes* ret = new (storage) bytes();
ret->arr.resize(PyString_Size(x));
memcpy(&ret->arr[0], PyString_AsString(x), ret->arr.size());
data->convertible = storage;
#endif
}
};
object client_fingerprint_(peer_id const& id) object client_fingerprint_(peer_id const& id)
{ {
boost::optional<fingerprint> result = client_fingerprint(id); boost::optional<fingerprint> result = client_fingerprint(id);
return result ? object(*result) : object(); return result ? object(*result) : object();
} }
entry bdecode_(std::string const& data) entry bdecode_(bytes const& data)
{ {
return bdecode(data.begin(), data.end()); return bdecode(data.arr.begin(), data.arr.end());
} }
std::string bencode_(entry const& e) bytes bencode_(entry const& e)
{ {
std::string result; bytes result;
bencode(std::back_inserter(result), e); bencode(std::back_inserter(result.arr), e);
return result; return result;
} }
void bind_utility() void bind_utility()
{ {
// TODO: it would be nice to install converters for sha1_hash as well
to_python_converter<bytes, bytes_to_python>();
bytes_from_python();
def("identify_client", &libtorrent::identify_client); def("identify_client", &libtorrent::identify_client);
def("client_fingerprint", &client_fingerprint_); def("client_fingerprint", &client_fingerprint_);
def("bdecode", &bdecode_); def("bdecode", &bdecode_);

View File

@ -124,7 +124,9 @@ cannot rely on ``error_code::message()`` to generate your strings.
The numeric values of the errors are part of the API and will stay the same, although The numeric values of the errors are part of the API and will stay the same, although
new error codes may be appended at the end. new error codes may be appended at the end.
Here's a simple example of how to translate error codes:: Here's a simple example of how to translate error codes:
.. code:: c++
std::string error_code_to_string(boost::system::error_code const& ec) std::string error_code_to_string(boost::system::error_code const& ec)
{ {

View File

@ -33,44 +33,51 @@ POSSIBILITY OF SUCH DAMAGE.
#ifndef TORRENT_SLIDING_AVERAGE_HPP_INCLUDED #ifndef TORRENT_SLIDING_AVERAGE_HPP_INCLUDED
#define TORRENT_SLIDING_AVERAGE_HPP_INCLUDED #define TORRENT_SLIDING_AVERAGE_HPP_INCLUDED
#include <boost/cstdint.hpp>
namespace libtorrent namespace libtorrent
{ {
// a sliding average accumulator. Add samples to it and it // an exponential moving average accumulator. Add samples to it and it keeps
// keeps track of a sliding mean value and an average deviation // track of a moving mean value and an average deviation
template <int history_size> template <int inverted_gain>
struct sliding_average struct sliding_average
{ {
sliding_average(): m_mean(-1), m_average_deviation(-1) {} sliding_average(): m_mean(0), m_average_deviation(0), m_num_samples(0) {}
void add_sample(int s) void add_sample(int s)
{ {
TORRENT_ASSERT(s >= 0); // fixed point
if (s < 0) s = 0; s *= 64;
if (m_mean == -1) int deviation;
{
m_mean = s;
return;
}
int deviation = abs(m_mean - s);
m_mean = m_mean - m_mean / history_size + s / history_size; if (m_num_samples > 0)
deviation = abs(m_mean - s);
if (m_average_deviation == -1) if (m_num_samples < inverted_gain)
{ ++m_num_samples;
m_average_deviation = deviation;
return; m_mean += (s - m_mean) / m_num_samples;
if (m_num_samples > 1) {
// the the exact same thing for deviation off the mean except -1 on
// the samples, because the number of deviation samples always lags
// behind by 1 (you need to actual samples to have a single deviation
// sample).
m_average_deviation += (deviation - m_average_deviation) / (m_num_samples - 1);
} }
m_average_deviation = m_average_deviation - m_average_deviation
/ history_size + deviation / history_size;
} }
int mean() const { return m_mean != -1 ? m_mean : 0; } int mean() const { return m_num_samples > 0 ? (m_mean + 32) / 64 : 0; }
int avg_deviation() const { return m_average_deviation != -1 ? m_average_deviation : 0; } int avg_deviation() const { return m_num_samples > 1 ? (m_average_deviation + 32) / 64 : 0; }
private: private:
// both of these are fixed point values (* 64)
int m_mean; int m_mean;
int m_average_deviation; int m_average_deviation;
// the number of samples we have received, but no more than inverted_gain
// this is the effective inverted_gain
int m_num_samples;
}; };
struct average_accumulator struct average_accumulator
@ -100,7 +107,7 @@ struct average_accumulator
} }
int m_num_samples; int m_num_samples;
size_type m_sample_sum; boost::uint64_t m_sample_sum;
}; };
} }

View File

@ -89,6 +89,7 @@ feature launcher : none valgrind : composite ;
feature.compose <launcher>valgrind : <testing.launcher>"valgrind --tool=memcheck -v --num-callers=20 --read-var-info=yes --track-origins=yes --error-exitcode=222 --suppressions=valgrind_suppressions.txt" <valgrind>on ; feature.compose <launcher>valgrind : <testing.launcher>"valgrind --tool=memcheck -v --num-callers=20 --read-var-info=yes --track-origins=yes --error-exitcode=222 --suppressions=valgrind_suppressions.txt" <valgrind>on ;
test-suite libtorrent : test-suite libtorrent :
[ run test_sliding_average.cpp ]
[ run test_socket_io.cpp ] [ run test_socket_io.cpp ]
[ run test_random.cpp ] [ run test_random.cpp ]
[ run test_utf8.cpp ] [ run test_utf8.cpp ]

View File

@ -58,7 +58,8 @@ test_programs = \
test_remap_files \ test_remap_files \
test_gzip \ test_gzip \
test_utf8 \ test_utf8 \
test_socket_io test_socket_io \
test_sliding_average
if ENABLE_TESTS if ENABLE_TESTS
check_PROGRAMS = $(test_programs) check_PROGRAMS = $(test_programs)
@ -188,6 +189,7 @@ test_remap_files_SOURCES = test_remap_files.cpp
test_gzip_SOURCES = test_gzip.cpp test_gzip_SOURCES = test_gzip.cpp
test_utf8_SOURCES = test_utf8.cpp test_utf8_SOURCES = test_utf8.cpp
test_socket_io_SOURCES = test_socket_io.cpp test_socket_io_SOURCES = test_socket_io.cpp
test_sliding_average_SOURCES = test_sliding_average.cpp
LDADD = libtest.la $(top_builddir)/src/libtorrent-rasterbar.la LDADD = libtest.la $(top_builddir)/src/libtorrent-rasterbar.la

View File

@ -0,0 +1,95 @@
/*
Copyright (c) 2014, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.hpp"
#include "libtorrent/sliding_average.hpp"
// normal distributed samples. mean=60 stddev=10
int samples[] = {
49, 51, 60, 46, 65, 53, 76, 59, 57, 54, 56, 51, 45, 80, 53, 62,
69, 67, 66, 56, 56, 61, 52, 61, 61, 62, 59, 53, 48, 68, 47, 47,
63, 51, 53, 54, 46, 65, 64, 64, 45, 68, 64, 66, 53, 42, 57, 58,
57, 47, 55, 59, 64, 61, 37, 67, 55, 52, 60, 60, 44, 57, 50, 77,
56, 54, 49, 68, 66, 64, 47, 60, 46, 47, 81, 74, 65, 62, 44, 75,
65, 43, 58, 59, 53, 67, 49, 51, 33, 47, 49, 50, 54, 48, 55, 80,
67, 51, 66, 52, 48, 57, 30, 51, 72, 65, 78, 56, 74, 68, 49, 66,
63, 57, 61, 62, 64, 62, 61, 52, 67, 64, 59, 61, 69, 60, 54, 69 };
int test_main()
{
using namespace libtorrent;
// make sure we react quickly for the first few samples
{
sliding_average<10> avg;
avg.add_sample(-10);
avg.add_sample(10);
TEST_EQUAL(avg.mean(), 0);
}
{
sliding_average<10> avg;
avg.add_sample(10);
avg.add_sample(20);
TEST_EQUAL(avg.mean(), 15);
}
// make sure we converge
{
sliding_average<10> avg;
avg.add_sample(100);
for (int i = 0; i < 20; ++i)
avg.add_sample(10);
TEST_CHECK(abs(avg.mean() - 10) <= 3);
}
{
sliding_average<10> avg;
avg.add_sample(-100);
for (int i = 0; i < 20; ++i)
avg.add_sample(-10);
TEST_CHECK(abs(avg.mean() + 10) <= 3);
}
// test with a more realistic input
{
sliding_average<10> avg;
for (int i = 0; i < sizeof(samples)/sizeof(samples[0]); ++i)
avg.add_sample(samples[i]);
TEST_CHECK(abs(avg.mean() - 60) <= 3);
}
return 0;
}