forked from premiere/premiere-libtorrent
merged RC_1_1 into master
This commit is contained in:
commit
867b83ccda
|
@ -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 ..
|
||||
|
|
|
@ -87,6 +87,7 @@ set(sources
|
|||
torrent_info
|
||||
torrent_peer
|
||||
torrent_peer_allocator
|
||||
torrent_status
|
||||
tracker_manager
|
||||
http_tracker_connection
|
||||
utf8
|
||||
|
|
1
Jamfile
1
Jamfile
|
@ -626,6 +626,7 @@ SOURCES =
|
|||
torrent_info
|
||||
torrent_peer
|
||||
torrent_peer_allocator
|
||||
torrent_status
|
||||
time
|
||||
tracker_manager
|
||||
http_tracker_connection
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/alert.hpp>
|
||||
#include <libtorrent/alert_types.hpp>
|
||||
#include <libtorrent/piece_picker.hpp> // for piece_block
|
||||
#include <libtorrent/session_stats.hpp>
|
||||
#include <memory>
|
||||
#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)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <libtorrent/sha1_hash.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include "bytes.hpp"
|
||||
|
||||
long get_hash(boost::python::object o)
|
||||
|
|
|
@ -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 <libtorrent/aux_/disable_warnings_push.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include <libtorrent/aux_/disable_warnings_pop.hpp>
|
||||
|
||||
#endif
|
||||
|
|
@ -9,7 +9,14 @@
|
|||
|
||||
struct bytes
|
||||
{
|
||||
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;
|
||||
};
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
|
||||
using namespace boost::python;
|
||||
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/create_torrent.hpp>
|
||||
#include <libtorrent/file_storage.hpp>
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include "optional.hpp"
|
||||
#include <boost/version.hpp>
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/session.hpp>
|
||||
#include "bytes.hpp"
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <libtorrent/bdecode.hpp>
|
||||
#include <libtorrent/upnp.hpp>
|
||||
#include <libtorrent/socks5_stream.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
|
||||
using namespace boost::python;
|
||||
using namespace libtorrent;
|
||||
|
|
|
@ -3,12 +3,7 @@
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <libtorrent/fingerprint.hpp>
|
||||
|
||||
#include <libtorrent/aux_/disable_warnings_push.hpp>
|
||||
|
||||
#include <boost/python.hpp>
|
||||
|
||||
#include <libtorrent/aux_/disable_warnings_pop.hpp>
|
||||
#include "boost_python.hpp"
|
||||
|
||||
void bind_fingerprint()
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <libtorrent/ip_filter.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include "gil.hpp"
|
||||
|
||||
using namespace boost::python;
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/session.hpp>
|
||||
#include <libtorrent/torrent.hpp>
|
||||
#include <libtorrent/magnet_uri.hpp>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#ifndef OPTIONAL_070108_HPP
|
||||
# define OPTIONAL_070108_HPP
|
||||
|
||||
# include <boost/python.hpp>
|
||||
# include "boost_python.hpp"
|
||||
# include <boost/optional.hpp>
|
||||
|
||||
template <class T>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <libtorrent/peer_info.hpp>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <boost/python/iterator.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
|
@ -136,7 +136,26 @@ namespace
|
|||
return boost::make_shared<lt::session>(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<session_settings> 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<dict>(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<boost::shared_ptr<torrent_info> >(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<torrent_info>(
|
||||
extract<torrent_info const&>(params["ti"]));
|
||||
}
|
||||
|
||||
|
||||
if (params.has_key("info_hash"))
|
||||
p.info_hash = sha1_hash(bytes(extract<bytes>(params["info_hash"])).arr);
|
||||
|
@ -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))
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/session.hpp>
|
||||
|
||||
using namespace boost::python;
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <string>
|
||||
|
||||
using namespace boost::python;
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <boost/python/tuple.hpp>
|
||||
#include <boost/python/stl_iterator.hpp>
|
||||
#include <libtorrent/torrent_handle.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/torrent_status.hpp>
|
||||
|
@ -121,59 +122,44 @@ list get_peer_info(torrent_handle const& handle)
|
|||
return result;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
T extract_fn(object o)
|
||||
{
|
||||
return boost::python::extract<T>(o);
|
||||
}
|
||||
}
|
||||
|
||||
void prioritize_pieces(torrent_handle& info, object o)
|
||||
{
|
||||
std::vector<int> result;
|
||||
stl_input_iterator<object> 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<std::pair<int, int> >(*begin).check();
|
||||
|
||||
if (is_piece_list)
|
||||
{
|
||||
std::vector<std::pair<int, int> > piece_list;
|
||||
try
|
||||
{
|
||||
object iter_obj = object( handle<>( PyObject_GetIter( o.ptr() ) ));
|
||||
while( 1 )
|
||||
{
|
||||
object obj = extract<object>( iter_obj.attr( "next" )() );
|
||||
extract<int const> val1(obj);
|
||||
if (val1.check())
|
||||
{
|
||||
result.push_back(val1);
|
||||
continue;
|
||||
}
|
||||
extract<std::pair<int, int> > val2(obj);
|
||||
if (val2.check())
|
||||
{
|
||||
piece_list.push_back(val2);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( error_already_set )
|
||||
{
|
||||
PyErr_Clear();
|
||||
if (result.size())
|
||||
info.prioritize_pieces(result);
|
||||
else
|
||||
std::transform(begin, end, std::back_inserter(piece_list)
|
||||
, &extract_fn<std::pair<int, int> >);
|
||||
info.prioritize_pieces(piece_list);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<int> priority_vector;
|
||||
std::transform(begin, end, std::back_inserter(priority_vector)
|
||||
, &extract_fn<int>);
|
||||
info.prioritize_pieces(priority_vector);
|
||||
}
|
||||
}
|
||||
|
||||
void prioritize_files(torrent_handle& info, object o)
|
||||
{
|
||||
std::vector<int> result;
|
||||
try
|
||||
{
|
||||
object iter_obj = object( handle<>( PyObject_GetIter( o.ptr() ) ));
|
||||
while( 1 )
|
||||
{
|
||||
object obj = extract<object>( iter_obj.attr( "next" )() );
|
||||
result.push_back(extract<int const>( obj ));
|
||||
}
|
||||
}
|
||||
catch( error_already_set )
|
||||
{
|
||||
PyErr_Clear();
|
||||
info.prioritize_files(result);
|
||||
return;
|
||||
}
|
||||
stl_input_iterator<int const> begin(o), end;
|
||||
info.prioritize_files(std::vector<int> (begin, end));
|
||||
}
|
||||
|
||||
list file_priorities(torrent_handle& handle)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#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)
|
||||
|
|
|
@ -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 <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include <libtorrent/torrent_status.hpp>
|
||||
#include <libtorrent/torrent_info.hpp>
|
||||
#include <libtorrent/bitfield.hpp>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <libtorrent/identify_client.hpp>
|
||||
#include <libtorrent/bencode.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
#include "bytes.hpp"
|
||||
|
||||
using namespace boost::python;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <libtorrent/version.hpp>
|
||||
#include <boost/python.hpp>
|
||||
#include "boost_python.hpp"
|
||||
|
||||
using namespace boost::python;
|
||||
using libtorrent::version;
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <libtorrent/torrent_status.hpp>
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 <boost/integer_traits.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/assert.hpp"
|
||||
|
||||
namespace libtorrent {
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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<io_service::work> 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; }
|
||||
|
||||
|
|
|
@ -33,12 +33,16 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#ifndef TORRENT_HASHER_HPP_INCLUDED
|
||||
#define TORRENT_HASHER_HPP_INCLUDED
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
#include "libtorrent/config.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#ifdef TORRENT_USE_GCRYPT
|
||||
#include <gcrypt.h>
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 <boost/cstdint.hpp>
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <algorithm> // for copy
|
||||
#include <cstring> // for memcpy
|
||||
|
|
|
@ -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<int> 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -113,17 +113,21 @@ namespace libtorrent
|
|||
template <class SocketOption>
|
||||
void get_option(SocketOption const& 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);
|
||||
}
|
||||
|
||||
template <class SocketOption>
|
||||
void set_option(SocketOption const& opt, error_code& ec)
|
||||
{
|
||||
if (opt.level(udp::v4()) != IPPROTO_IPV6)
|
||||
m_ipv4_sock.set_option(opt, ec);
|
||||
#if TORRENT_USE_IPV6
|
||||
if (opt.level(udp::v6()) != IPPROTO_IP)
|
||||
m_ipv6_sock.set_option(opt, ec);
|
||||
#endif
|
||||
}
|
||||
|
@ -131,6 +135,11 @@ namespace libtorrent
|
|||
template <class SocketOption>
|
||||
void get_option(SocketOption& opt, error_code& 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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit ce7d45687bb10dac8f533cf359afc7c78de705f7
|
||||
Subproject commit 0151d5c17fa3f4cf0ce518d0b8f90a23792c9b24
|
|
@ -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 <typename Announce, typename Test1, typename Test2>
|
||||
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<torrent_info> 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<char> buf;
|
||||
bencode(std::back_inserter(buf), e);
|
||||
error_code ec;
|
||||
return boost::make_shared<torrent_info>(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<std::string, std::string>& 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<std::string, std::string>& 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<std::string, std::string>& 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
|
||||
|
|
|
@ -55,8 +55,6 @@ 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
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -30,7 +30,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
*/
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/bandwidth_queue_entry.hpp"
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -183,19 +183,21 @@ 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()))
|
||||
}
|
||||
}
|
||||
|
||||
#if TORRENT_USE_IPV6
|
||||
if (tracker_req().ipv6 != address_v6() && !i2p)
|
||||
{
|
||||
// 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());
|
||||
}
|
||||
*/
|
||||
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)
|
||||
|
|
|
@ -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<char> buf;
|
||||
|
||||
|
@ -311,32 +313,51 @@ namespace libtorrent
|
|||
for (; piece < end; ++piece)
|
||||
{
|
||||
boost::unordered_map<int, int>::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);
|
||||
// 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<int, int>::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;
|
||||
piece_offset = 0;
|
||||
size -= block_to_copy;
|
||||
|
|
|
@ -1893,21 +1893,15 @@ namespace libtorrent
|
|||
namespace
|
||||
{
|
||||
int append_blocks(std::vector<piece_block>& dst, std::vector<piece_block>& 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;
|
||||
|
@ -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;
|
||||
|
|
|
@ -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 <boost/shared_ptr.hpp>
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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 = "_";
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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() {}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -124,11 +124,11 @@ boost::shared_ptr<default_storage> 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<char> buf;
|
||||
file_pool fp;
|
||||
io_service ios;
|
||||
disk_buffer_pool dp(16 * 1024, ios, boost::bind(&nop));
|
||||
boost::shared_ptr<default_storage> 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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue