merged RC_1_1 into master
This commit is contained in:
commit
6cf5ac9dd1
|
@ -14,6 +14,8 @@
|
|||
|
||||
1.1.1 release
|
||||
|
||||
* added a new "preformatted" type to bencode entry variant type
|
||||
* improved Socks5 support and test coverage
|
||||
* fix set_settings in python binding
|
||||
* Added missing alert categories in python binding
|
||||
* Added dht_get_peers_reply_alert alert in python binding
|
||||
|
|
|
@ -1322,7 +1322,7 @@ namespace libtorrent
|
|||
// was opened for listening.
|
||||
struct TORRENT_EXPORT listen_succeeded_alert final : alert
|
||||
{
|
||||
enum socket_type_t { tcp, tcp_ssl, udp, utp_ssl };
|
||||
enum socket_type_t { tcp, tcp_ssl, udp, i2p, socks5, utp_ssl };
|
||||
|
||||
// internal
|
||||
listen_succeeded_alert(aux::stack_allocator& alloc, tcp::endpoint const& ep
|
||||
|
@ -1747,8 +1747,8 @@ namespace libtorrent
|
|||
// an incoming connection, through any mean. The most straight-forward ways
|
||||
// of accepting incoming connections are through the TCP listen socket and
|
||||
// the UDP listen socket for uTP sockets. However, connections may also be
|
||||
// accepted offer a Socks5 or i2p listen socket, or via a torrent specific
|
||||
// listen socket for SSL torrents.
|
||||
// accepted through a Socks5 or i2p listen socket, or via an SSL listen
|
||||
// socket.
|
||||
struct TORRENT_EXPORT incoming_connection_alert final : alert
|
||||
{
|
||||
// internal
|
||||
|
|
|
@ -256,6 +256,8 @@ namespace libtorrent
|
|||
void async_accept(boost::shared_ptr<tcp::acceptor> const& listener, bool ssl);
|
||||
void on_accept_connection(boost::shared_ptr<socket_type> const& s
|
||||
, boost::weak_ptr<tcp::acceptor> listener, error_code const& e, bool ssl);
|
||||
void on_socks_listen(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e);
|
||||
void on_socks_accept(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e);
|
||||
|
||||
|
|
|
@ -210,6 +210,10 @@ namespace libtorrent
|
|||
write_char(out, 'e');
|
||||
ret += 2;
|
||||
break;
|
||||
case entry::preformatted_t:
|
||||
std::copy(e.preformatted().begin(), e.preformatted().end(), out);
|
||||
ret += e.preformatted().size();
|
||||
break;
|
||||
case entry::undefined_t:
|
||||
// trying to encode a structure with uninitialized values!
|
||||
// TORRENT_ASSERT_VAL(false, e.type());
|
||||
|
|
|
@ -50,11 +50,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace libtorrent
|
||||
{
|
||||
|
||||
// TODO: 2 facto these functions out
|
||||
TORRENT_EXTRA_EXPORT bool is_local(address const& a);
|
||||
TORRENT_EXTRA_EXPORT bool is_loopback(address const& addr);
|
||||
TORRENT_EXTRA_EXPORT bool is_any(address const& addr);
|
||||
TORRENT_EXTRA_EXPORT bool is_teredo(address const& addr);
|
||||
TORRENT_EXTRA_EXPORT int cidr_distance(address const& a1, address const& a2);
|
||||
bool is_ip_address(char const* host);
|
||||
|
||||
// determines if the operating system supports IPv6
|
||||
TORRENT_EXTRA_EXPORT bool supports_ipv6();
|
||||
|
|
|
@ -108,6 +108,7 @@ namespace libtorrent
|
|||
typedef std::string string_type;
|
||||
typedef std::list<entry> list_type;
|
||||
typedef boost::int64_t integer_type;
|
||||
typedef std::vector<char> preformatted_type;
|
||||
|
||||
// the types an entry can have
|
||||
enum data_type
|
||||
|
@ -116,7 +117,8 @@ namespace libtorrent
|
|||
string_t,
|
||||
list_t,
|
||||
dictionary_t,
|
||||
undefined_t
|
||||
undefined_t,
|
||||
preformatted_t
|
||||
};
|
||||
|
||||
// returns the concrete type of the entry
|
||||
|
@ -129,6 +131,7 @@ namespace libtorrent
|
|||
entry(string_type const&);
|
||||
entry(list_type const&);
|
||||
entry(integer_type const&);
|
||||
entry(preformatted_type const&);
|
||||
|
||||
// construct an empty entry of the specified type.
|
||||
// see data_type enum.
|
||||
|
@ -160,6 +163,7 @@ namespace libtorrent
|
|||
entry& operator=(string_type const&);
|
||||
entry& operator=(list_type const&);
|
||||
entry& operator=(integer_type const&);
|
||||
entry& operator=(preformatted_type const&);
|
||||
|
||||
// The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions
|
||||
// are accessors that return the respective type. If the ``entry`` object
|
||||
|
@ -216,6 +220,8 @@ namespace libtorrent
|
|||
const list_type& list() const;
|
||||
dictionary_type& dict();
|
||||
const dictionary_type& dict() const;
|
||||
preformatted_type& preformatted();
|
||||
const preformatted_type& preformatted() const;
|
||||
|
||||
// swaps the content of *this* with ``e``.
|
||||
void swap(entry& e);
|
||||
|
@ -268,17 +274,19 @@ namespace libtorrent
|
|||
// assumes sizeof(map<string, char>) == sizeof(map<string, entry>)
|
||||
// and sizeof(list<char>) == sizeof(list<entry>)
|
||||
enum { union_size
|
||||
= max4<sizeof(std::list<char>)
|
||||
= max5<sizeof(std::list<char>)
|
||||
, sizeof(std::map<std::string, char>)
|
||||
, sizeof(string_type)
|
||||
, sizeof(integer_type)>::value
|
||||
, sizeof(integer_type)
|
||||
, sizeof(preformatted_type)>::value
|
||||
};
|
||||
#else
|
||||
enum { union_size
|
||||
= max4<sizeof(list_type)
|
||||
= max5<sizeof(list_type)
|
||||
, sizeof(dictionary_type)
|
||||
, sizeof(string_type)
|
||||
, sizeof(integer_type)>::value
|
||||
, sizeof(integer_type)
|
||||
, sizeof(preformatted_type)>::value
|
||||
};
|
||||
#endif
|
||||
integer_type data[(union_size + sizeof(integer_type) - 1)
|
||||
|
|
|
@ -37,10 +37,12 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/make_shared.hpp>
|
||||
|
||||
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
||||
|
||||
#include "libtorrent/proxy_base.hpp"
|
||||
#include "libtorrent/broadcast_socket.hpp" // for is_ip_address
|
||||
#include "libtorrent/assert.hpp"
|
||||
#include "libtorrent/debug.hpp"
|
||||
|
||||
|
@ -96,7 +98,7 @@ public:
|
|||
|
||||
void set_command(int c)
|
||||
{
|
||||
TORRENT_ASSERT(c >= socks5_connect && c <=socks5_udp_associate);
|
||||
TORRENT_ASSERT(c >= socks5_connect && c <= socks5_udp_associate);
|
||||
m_command = c;
|
||||
}
|
||||
|
||||
|
@ -107,19 +109,43 @@ public:
|
|||
m_password = password;
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void async_accept(Handler const& handler)
|
||||
{
|
||||
TORRENT_ASSERT(m_listen == 1);
|
||||
TORRENT_ASSERT(m_command == socks5_bind);
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
error_code e;
|
||||
connect1(e, boost::make_shared<handler_type>(handler));
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void async_listen(tcp::endpoint const& ep, Handler const& handler)
|
||||
{
|
||||
m_command = socks5_bind;
|
||||
|
||||
m_remote_endpoint = ep;
|
||||
|
||||
// to avoid unnecessary copying of the handler,
|
||||
// store it in a shaed_ptr
|
||||
boost::shared_ptr<handler_type> h(new handler_type(handler));
|
||||
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
add_outstanding_async("socks5_stream::name_lookup");
|
||||
#endif
|
||||
tcp::resolver::query q(m_hostname, to_string(m_port).data());
|
||||
m_resolver.async_resolve(q, boost::bind(
|
||||
&socks5_stream::name_lookup, this, _1, _2, h));
|
||||
}
|
||||
|
||||
void set_dst_name(std::string const& host)
|
||||
{
|
||||
// TODO: 3 enable this assert and fix remaining causes of it triggering
|
||||
/*
|
||||
#if TORRENT_USE_ASSERTS
|
||||
error_code ec;
|
||||
address::from_string(host, ec);
|
||||
// if this assert trips, set_dst_name() is called wth an IP address rather
|
||||
// than a hostname. Instead, resolve the IP into an address and pass it to
|
||||
// async_connect instead
|
||||
TORRENT_ASSERT(ec);
|
||||
#endif
|
||||
*/
|
||||
TORRENT_ASSERT(!is_ip_address(host.c_str()));
|
||||
m_dst_name = host;
|
||||
if (m_dst_name.size() > 255)
|
||||
m_dst_name.resize(255);
|
||||
|
@ -139,14 +165,27 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
endpoint_type local_endpoint() const
|
||||
{
|
||||
return m_local_endpoint;
|
||||
}
|
||||
#endif
|
||||
|
||||
endpoint_type local_endpoint(error_code&) const
|
||||
{
|
||||
return m_local_endpoint;
|
||||
}
|
||||
|
||||
|
||||
// TODO: 2 add async_connect() that takes a hostname and port as well
|
||||
template <class Handler>
|
||||
void async_connect(endpoint_type const& endpoint, Handler const& handler)
|
||||
{
|
||||
// make sure we don't try to connect to INADDR_ANY. binding is fine,
|
||||
// and using a hostname is fine on SOCKS version 5.
|
||||
TORRENT_ASSERT(m_command == socks5_bind
|
||||
|| endpoint.address() != address()
|
||||
TORRENT_ASSERT(m_command != socks5_bind);
|
||||
TORRENT_ASSERT(endpoint.address() != address()
|
||||
|| (!m_dst_name.empty() && m_version == 5));
|
||||
|
||||
m_remote_endpoint = endpoint;
|
||||
|
@ -190,6 +229,11 @@ private:
|
|||
std::string m_user;
|
||||
std::string m_password;
|
||||
std::string m_dst_name;
|
||||
|
||||
// when listening via a socks proxy, this is the IP and port our listen
|
||||
// socket bound to
|
||||
endpoint_type m_local_endpoint;
|
||||
|
||||
int m_version;
|
||||
|
||||
// the socks command to send for this connection (connect, bind,
|
||||
|
|
|
@ -24,6 +24,7 @@ project
|
|||
;
|
||||
|
||||
alias libtorrent-sims :
|
||||
[ run test_socks5.cpp ]
|
||||
[ run test_checking.cpp ]
|
||||
[ run test_optimistic_unchoke.cpp ]
|
||||
[ run test_transfer.cpp ]
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015, 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.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef SIMULATION_FAKE_PEER_HPP
|
||||
#define SIMULATION_FAKE_PEER_HPP
|
||||
|
||||
#include <array>
|
||||
#include "test.hpp"
|
||||
#include "simulator/simulator.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/socket_io.hpp"
|
||||
#include "libtorrent/torrent_handle.hpp"
|
||||
#include "libtorrent/sha1_hash.hpp"
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
|
||||
using namespace sim;
|
||||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
struct fake_peer
|
||||
{
|
||||
fake_peer(simulation& sim, char const* ip)
|
||||
: m_ios(sim, asio::ip::address::from_string(ip))
|
||||
, m_acceptor(m_ios)
|
||||
, m_in_socket(m_ios)
|
||||
, m_out_socket(m_ios)
|
||||
, m_tripped(false)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
m_acceptor.open(asio::ip::tcp::v4(), ec);
|
||||
TEST_CHECK(!ec);
|
||||
m_acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v4::any(), 6881), ec);
|
||||
TEST_CHECK(!ec);
|
||||
m_acceptor.listen(10, ec);
|
||||
TEST_CHECK(!ec);
|
||||
|
||||
m_acceptor.async_accept(m_in_socket, [&] (boost::system::error_code const& ec)
|
||||
{
|
||||
// TODO: ideally we would kick off a read on the socket to verify that
|
||||
// we received a bittorrent handshake
|
||||
if (!ec) m_tripped = true;
|
||||
});
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_acceptor.close();
|
||||
m_in_socket.close();
|
||||
m_out_socket.close();
|
||||
}
|
||||
|
||||
void connect_to(asio::ip::tcp::endpoint ep, lt::sha1_hash const& ih)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
boost::system::error_code ec;
|
||||
m_out_socket.async_connect(ep, std::bind(&fake_peer::write_handshake
|
||||
, this, _1, ih));
|
||||
}
|
||||
|
||||
bool tripped() const { return m_tripped; }
|
||||
|
||||
private:
|
||||
|
||||
void write_handshake(boost::system::error_code const& ec, lt::sha1_hash ih)
|
||||
{
|
||||
asio::ip::tcp::endpoint ep = m_out_socket.remote_endpoint();
|
||||
printf("fake_peer::connect (%s) -> (%d) %s\n"
|
||||
, lt::print_endpoint(ep).c_str(), ec.value()
|
||||
, ec.message().c_str());
|
||||
static char const handshake[]
|
||||
= "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
|
||||
" " // space for info-hash
|
||||
"aaaaaaaaaaaaaaaaaaaa" // peer-id
|
||||
"\0\0\0\x01\x02"; // interested
|
||||
int const len = sizeof(handshake) - 1;
|
||||
memcpy(m_out_buffer, handshake, len);
|
||||
memcpy(&m_out_buffer[28], ih.data(), 20);
|
||||
|
||||
asio::async_write(m_out_socket, asio::const_buffers_1(&m_out_buffer[0]
|
||||
, len), [=](boost::system::error_code const& ec, size_t bytes_transferred)
|
||||
{
|
||||
printf("fake_peer::write_handshake(%s) -> (%d) %s\n"
|
||||
, lt::print_endpoint(ep).c_str(), ec.value()
|
||||
, ec.message().c_str());
|
||||
this->m_out_socket.close();
|
||||
});
|
||||
}
|
||||
|
||||
char m_out_buffer[300];
|
||||
|
||||
asio::io_service m_ios;
|
||||
asio::ip::tcp::acceptor m_acceptor;
|
||||
asio::ip::tcp::socket m_in_socket;
|
||||
asio::ip::tcp::socket m_out_socket;
|
||||
bool m_tripped;
|
||||
};
|
||||
|
||||
inline void add_fake_peers(lt::torrent_handle h)
|
||||
{
|
||||
// add the fake peers
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
char ep[30];
|
||||
snprintf(ep, sizeof(ep), "60.0.0.%d", i);
|
||||
h.connect_peer(lt::tcp::endpoint(
|
||||
lt::address_v4::from_string(ep), 6881));
|
||||
}
|
||||
}
|
||||
|
||||
inline void check_tripped(std::array<fake_peer*, 5>& test_peers, std::array<bool, 5> expected)
|
||||
{
|
||||
int idx = 0;
|
||||
for (auto p : test_peers)
|
||||
{
|
||||
TEST_EQUAL(p->tripped(), expected[idx]);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -41,47 +41,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_types.hpp"
|
||||
#include "simulator/simulator.hpp"
|
||||
#include "simulator/utils.hpp"
|
||||
#include "fake_peer.hpp"
|
||||
#include "utils.hpp" // for print_alerts
|
||||
|
||||
using namespace sim;
|
||||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
struct fake_peer
|
||||
{
|
||||
fake_peer(simulation& sim, char const* ip)
|
||||
: m_ios(sim, asio::ip::address::from_string(ip))
|
||||
, m_acceptor(m_ios)
|
||||
, m_socket(m_ios)
|
||||
, m_tripped(false)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
m_acceptor.open(asio::ip::tcp::v4(), ec);
|
||||
TEST_CHECK(!ec);
|
||||
m_acceptor.bind(asio::ip::tcp::endpoint(asio::ip::address_v4::any(), 6881), ec);
|
||||
TEST_CHECK(!ec);
|
||||
m_acceptor.listen(10, ec);
|
||||
TEST_CHECK(!ec);
|
||||
|
||||
m_acceptor.async_accept(m_socket, [&] (boost::system::error_code const& ec)
|
||||
{ if (!ec) m_tripped = true; });
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
m_acceptor.close();
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
bool tripped() const { return m_tripped; }
|
||||
|
||||
private:
|
||||
asio::io_service m_ios;
|
||||
asio::ip::tcp::acceptor m_acceptor;
|
||||
asio::ip::tcp::socket m_socket;
|
||||
bool m_tripped;
|
||||
};
|
||||
|
||||
template <typename Setup, typename HandleAlerts, typename Test>
|
||||
void run_test(Setup const& setup
|
||||
, HandleAlerts const& on_alert
|
||||
|
@ -134,28 +100,6 @@ void run_test(Setup const& setup
|
|||
sim.run();
|
||||
}
|
||||
|
||||
void add_fake_peers(lt::torrent_handle h)
|
||||
{
|
||||
// add the fake peers
|
||||
for (int i = 0; i < 5; ++i)
|
||||
{
|
||||
char ep[30];
|
||||
snprintf(ep, sizeof(ep), "60.0.0.%d", i);
|
||||
h.connect_peer(lt::tcp::endpoint(
|
||||
lt::address_v4::from_string(ep), 6881));
|
||||
}
|
||||
}
|
||||
|
||||
void check_tripped(std::array<fake_peer*, 5>& test_peers, std::array<bool, 5> expected)
|
||||
{
|
||||
int idx = 0;
|
||||
for (auto p : test_peers)
|
||||
{
|
||||
TEST_EQUAL(p->tripped(), expected[idx]);
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
|
||||
void add_ip_filter(lt::session& ses)
|
||||
{
|
||||
lt::ip_filter filter;
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 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/session.hpp"
|
||||
#include "libtorrent/torrent_handle.hpp"
|
||||
#include "libtorrent/settings_pack.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "libtorrent/deadline_timer.hpp"
|
||||
#include "simulator/http_server.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "create_torrent.hpp"
|
||||
#include "simulator/simulator.hpp"
|
||||
#include "setup_swarm.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "simulator/socks_server.hpp"
|
||||
#include "simulator/utils.hpp"
|
||||
#include "fake_peer.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using namespace sim;
|
||||
using namespace libtorrent;
|
||||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
std::unique_ptr<sim::asio::io_service> make_io_service(sim::simulation& sim, int i)
|
||||
{
|
||||
char ep[30];
|
||||
snprintf(ep, sizeof(ep), "50.0.%d.%d", (i + 1) >> 8, (i + 1) & 0xff);
|
||||
return std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
|
||||
sim, address_v4::from_string(ep)));
|
||||
}
|
||||
|
||||
// this is the general template for these tests. create the session with custom
|
||||
// settings (Settings), set up the test, by adding torrents with certain
|
||||
// arguments (Setup), run the test and verify the end state (Test)
|
||||
template <typename Setup, typename HandleAlerts, typename Test>
|
||||
void run_test(Setup const& setup
|
||||
, HandleAlerts const& on_alert
|
||||
, Test const& test)
|
||||
{
|
||||
// setup the simulation
|
||||
sim::default_config network_cfg;
|
||||
sim::simulation sim{network_cfg};
|
||||
std::unique_ptr<sim::asio::io_service> ios = make_io_service(sim, 0);
|
||||
lt::session_proxy zombie;
|
||||
|
||||
sim::asio::io_service proxy_ios{sim, addr("50.50.50.50") };
|
||||
sim::socks_server socks4(proxy_ios, 4444, 4);
|
||||
sim::socks_server socks5(proxy_ios, 5555, 5);
|
||||
|
||||
lt::settings_pack pack = settings();
|
||||
// create session
|
||||
std::shared_ptr<lt::session> ses = std::make_shared<lt::session>(pack, *ios);
|
||||
|
||||
// set up test, like adding torrents (customization point)
|
||||
setup(*ses);
|
||||
|
||||
// only monitor alerts for session 0 (the downloader)
|
||||
print_alerts(*ses, [=](lt::session& ses, lt::alert const* a) {
|
||||
on_alert(ses, a);
|
||||
});
|
||||
|
||||
lt::add_torrent_params params = create_torrent(1);
|
||||
params.flags &= ~lt::add_torrent_params::flag_auto_managed;
|
||||
params.flags &= ~lt::add_torrent_params::flag_paused;
|
||||
params.save_path = save_path(0);
|
||||
ses->async_add_torrent(params);
|
||||
|
||||
// set up a timer to fire later, to verify everything we expected to happen
|
||||
// happened
|
||||
sim::timer t(sim, lt::seconds(100), [&](boost::system::error_code const& ec)
|
||||
{
|
||||
fprintf(stderr, "shutting down\n");
|
||||
// shut down
|
||||
ses->set_alert_notify([] {});
|
||||
zombie = ses->abort();
|
||||
ses.reset();
|
||||
});
|
||||
|
||||
test(sim, *ses, params.ti);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_accept)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
bool incoming_connection = false;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
set_proxy(ses, settings_pack::socks5);
|
||||
},
|
||||
[&](lt::session& ses, lt::alert const* alert) {
|
||||
if (auto* a = lt::alert_cast<lt::incoming_connection_alert>(alert))
|
||||
{
|
||||
TEST_EQUAL(a->socket_type, 2);
|
||||
incoming_connection = true;
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, boost::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
// test connecting to the client via its socks5 listen port
|
||||
// TODO: maybe we could use peer_conn here instead
|
||||
fake_peer peer1(sim, "60.0.0.0");
|
||||
fake_peer peer2(sim, "60.0.0.1");
|
||||
|
||||
sim::timer t1(sim, lt::seconds(2), [&](boost::system::error_code const& ec)
|
||||
{
|
||||
peer1.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||
});
|
||||
|
||||
sim::timer t2(sim, lt::seconds(3), [&](boost::system::error_code const& ec)
|
||||
{
|
||||
peer2.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||
});
|
||||
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(incoming_connection, true);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks4_tcp_accept)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
bool incoming_connection = false;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
set_proxy(ses, settings_pack::socks4);
|
||||
},
|
||||
[&](lt::session& ses, lt::alert const* alert) {
|
||||
if (auto* a = lt::alert_cast<lt::incoming_connection_alert>(alert))
|
||||
{
|
||||
TEST_EQUAL(a->socket_type, 2);
|
||||
TEST_EQUAL(a->ip.address(), addr("60.0.0.0"))
|
||||
incoming_connection = true;
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, boost::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
fake_peer peer1(sim, "60.0.0.0");
|
||||
|
||||
sim::timer t1(sim, lt::seconds(2), [&](boost::system::error_code const& ec)
|
||||
{
|
||||
peer1.connect_to(tcp::endpoint(addr("50.50.50.50"), 6881), ti->info_hash());
|
||||
});
|
||||
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(incoming_connection, true);
|
||||
}
|
||||
|
||||
// make sure a listen_succeeded_alert is issued when successfully listening on
|
||||
// incoming connections via a socks5 proxy
|
||||
TORRENT_TEST(socks4_tcp_listen_alert)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
bool listen_alert = false;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
set_proxy(ses, settings_pack::socks4);
|
||||
},
|
||||
[&](lt::session& ses, lt::alert const* alert) {
|
||||
if (auto* a = lt::alert_cast<lt::listen_succeeded_alert>(alert))
|
||||
{
|
||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||
{
|
||||
TEST_EQUAL(a->endpoint.address(), addr("50.50.50.50"));
|
||||
TEST_EQUAL(a->endpoint.port(), 6881);
|
||||
listen_alert = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, boost::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(listen_alert, true);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_listen_alert)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
bool listen_alert = false;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
set_proxy(ses, settings_pack::socks5);
|
||||
},
|
||||
[&](lt::session& ses, lt::alert const* alert) {
|
||||
if (auto* a = lt::alert_cast<lt::listen_succeeded_alert>(alert))
|
||||
{
|
||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||
{
|
||||
TEST_EQUAL(a->endpoint.address(), addr("50.50.50.50"));
|
||||
TEST_EQUAL(a->endpoint.port(), 6881);
|
||||
listen_alert = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, boost::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(listen_alert, true);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_announce)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
int tracker_port = -1;
|
||||
int alert_port = -1;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
set_proxy(ses, settings_pack::socks5);
|
||||
|
||||
lt::add_torrent_params params;
|
||||
params.info_hash = sha1_hash("abababababababababab");
|
||||
params.trackers.push_back("http://2.2.2.2:8080/announce");
|
||||
params.save_path = ".";
|
||||
ses.async_add_torrent(params);
|
||||
},
|
||||
[&alert_port](lt::session& ses, lt::alert const* alert) {
|
||||
if (auto* a = lt::alert_cast<lt::listen_succeeded_alert>(alert))
|
||||
{
|
||||
if (a->sock_type == listen_succeeded_alert::socks5)
|
||||
{
|
||||
alert_port = a->endpoint.port();
|
||||
}
|
||||
}
|
||||
},
|
||||
[&tracker_port](sim::simulation& sim, lt::session& ses
|
||||
, boost::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
sim::asio::io_service web_server(sim, address_v4::from_string("2.2.2.2"));
|
||||
// listen on port 8080
|
||||
sim::http_server http(web_server, 8080);
|
||||
|
||||
http.register_handler("/announce"
|
||||
, [&tracker_port](std::string method, std::string req
|
||||
, std::map<std::string, std::string>&)
|
||||
{
|
||||
if (req.find("&event=started") != std::string::npos)
|
||||
{
|
||||
std::string::size_type port_pos = req.find("&port=");
|
||||
TEST_CHECK(port_pos != std::string::npos);
|
||||
if (port_pos != std::string::npos)
|
||||
{
|
||||
tracker_port = atoi(req.c_str() + port_pos + 6);
|
||||
}
|
||||
}
|
||||
|
||||
return sim::send_response(200, "OK", 27) + "d8:intervali1800e5:peers0:e";
|
||||
});
|
||||
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(alert_port, tracker_port);
|
||||
TEST_CHECK(alert_port != -1);
|
||||
TEST_CHECK(tracker_port != -1);
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ void test_interval(int interval)
|
|||
std::vector<int> announces;
|
||||
|
||||
http.register_handler("/announce"
|
||||
, [&announces,interval,start](std::string method, std::string req
|
||||
, [&announces,interval,start](std::string method, std::string req
|
||||
, std::map<std::string, std::string>&)
|
||||
{
|
||||
boost::uint32_t seconds = chrono::duration_cast<lt::seconds>(
|
||||
|
@ -414,7 +414,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
|
|||
});
|
||||
|
||||
sim::timer t2(sim, lt::seconds(5 + delay)
|
||||
, [&ses,&test2](boost::system::error_code const& ec)
|
||||
, [&ses,&test2](boost::system::error_code const& ec)
|
||||
{
|
||||
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
||||
TEST_EQUAL(torrents.size(), 1);
|
||||
|
|
|
@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "settings.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/session_stats.hpp"
|
||||
#include "libtorrent/deadline_timer.hpp"
|
||||
#include "libtorrent/settings_pack.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
|
@ -52,6 +51,8 @@ using namespace sim;
|
|||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
const int connect_socks = 2;
|
||||
|
||||
template <typename Setup, typename HandleAlerts, typename Test>
|
||||
void run_test(
|
||||
Setup const& setup
|
||||
|
@ -111,7 +112,8 @@ void run_test(
|
|||
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
|
||||
if (auto ta = alert_cast<lt::torrent_added_alert>(a))
|
||||
{
|
||||
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
|
||||
ta->handle.connect_peer(lt::tcp::endpoint(
|
||||
(flags & connect_socks) ? proxy : peer1, 6881));
|
||||
}
|
||||
on_alert(ses, a);
|
||||
});
|
||||
|
@ -162,7 +164,7 @@ TORRENT_TEST(socks4_tcp)
|
|||
);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp)
|
||||
TORRENT_TEST(socks5_tcp_connect)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
run_test(
|
||||
|
@ -178,6 +180,26 @@ TORRENT_TEST(socks5_tcp)
|
|||
);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_accept)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
run_test(
|
||||
[](lt::session& ses0, lt::session& ses1)
|
||||
{
|
||||
// this time, the session accepting the connection is listening on a
|
||||
// socks5 BIND session
|
||||
set_proxy(ses1, settings_pack::socks5);
|
||||
filter_ips(ses0);
|
||||
},
|
||||
[](lt::session& ses, lt::alert const* alert) {},
|
||||
[](std::shared_ptr<lt::session> ses[2]) {
|
||||
TEST_EQUAL(is_seed(*ses[0]), true);
|
||||
},
|
||||
connect_socks
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
TORRENT_TEST(encryption_tcp)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
@ -260,10 +282,8 @@ TORRENT_TEST(no_proxy_utp)
|
|||
}
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: the socks server does not support UDP yet
|
||||
|
||||
/*
|
||||
// TOD: 3 figure out why this test is failing
|
||||
TORRENT_TEST(encryption_utp)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
@ -276,7 +296,10 @@ TORRENT_TEST(encryption_utp)
|
|||
}
|
||||
);
|
||||
}
|
||||
*/
|
||||
// TODO: the socks server does not support UDP yet
|
||||
|
||||
/*
|
||||
TORRENT_TEST(socks5_utp)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
|
|
@ -919,7 +919,7 @@ namespace libtorrent {
|
|||
|
||||
std::string listen_succeeded_alert::message() const
|
||||
{
|
||||
char const* type_str[] = { "TCP", "SSL/TCP", "UDP", "SSL/uTP" };
|
||||
char const* type_str[] = { "TCP", "SSL/TCP", "UDP", "i2p", "socks5", "SSL/uTP" };
|
||||
char ret[200];
|
||||
snprintf(ret, sizeof(ret), "successfully listening on [%s] %s"
|
||||
, type_str[sock_type], print_endpoint(endpoint).c_str());
|
||||
|
|
|
@ -62,6 +62,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
bool is_ip_address(char const* host)
|
||||
{
|
||||
error_code ec;
|
||||
address::from_string(host, ec);
|
||||
return !ec;
|
||||
}
|
||||
|
||||
bool is_local(address const& a)
|
||||
{
|
||||
TORRENT_TRY {
|
||||
|
|
|
@ -416,7 +416,9 @@ namespace libtorrent
|
|||
m_piece_hash.resize(m_files.num_pieces());
|
||||
for (int i = 0; i < num_pieces(); ++i) set_hash(i, ti.hash_for_piece(i));
|
||||
|
||||
m_info_dict = bdecode(&ti.metadata()[0], &ti.metadata()[0] + ti.metadata_size());
|
||||
boost::shared_array<char> const info = ti.metadata();
|
||||
int const size = ti.metadata_size();
|
||||
m_info_dict.preformatted().assign(&info[0], &info[0] + size);
|
||||
m_info_hash = ti.info_hash();
|
||||
}
|
||||
|
||||
|
@ -508,7 +510,8 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
entry& info = dict["info"];
|
||||
if (m_info_dict.type() == entry::dictionary_t)
|
||||
if (m_info_dict.type() == entry::dictionary_t
|
||||
|| m_info_dict.type() == entry::preformatted_t)
|
||||
{
|
||||
info = m_info_dict;
|
||||
return dict;
|
||||
|
|
|
@ -158,6 +158,7 @@ namespace libtorrent
|
|||
|
||||
entry& entry::operator=(const entry& e)
|
||||
{
|
||||
if (&e == this) return *this;
|
||||
destruct();
|
||||
copy(e);
|
||||
return *this;
|
||||
|
@ -261,6 +262,29 @@ namespace libtorrent
|
|||
return *reinterpret_cast<const dictionary_type*>(data);
|
||||
}
|
||||
|
||||
entry::preformatted_type& entry::preformatted()
|
||||
{
|
||||
if (m_type == undefined_t) construct(preformatted_t);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (m_type != preformatted_t) throw_type_error();
|
||||
#elif defined TORRENT_DEBUG
|
||||
TORRENT_ASSERT(m_type_queried);
|
||||
#endif
|
||||
TORRENT_ASSERT(m_type == preformatted_t);
|
||||
return *reinterpret_cast<preformatted_type*>(data);
|
||||
}
|
||||
|
||||
entry::preformatted_type const& entry::preformatted() const
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if (m_type != preformatted_t) throw_type_error();
|
||||
#elif defined TORRENT_DEBUG
|
||||
TORRENT_ASSERT(m_type_queried);
|
||||
#endif
|
||||
TORRENT_ASSERT(m_type == preformatted_t);
|
||||
return *reinterpret_cast<const preformatted_type*>(data);
|
||||
}
|
||||
|
||||
entry::entry()
|
||||
: m_type(undefined_t)
|
||||
{
|
||||
|
@ -339,6 +363,16 @@ namespace libtorrent
|
|||
m_type = int_t;
|
||||
}
|
||||
|
||||
entry::entry(preformatted_type const& v)
|
||||
: m_type(undefined_t)
|
||||
{
|
||||
#ifdef TORRENT_DEBUG
|
||||
m_type_queried = true;
|
||||
#endif
|
||||
new(data) preformatted_type(v);
|
||||
m_type = preformatted_t;
|
||||
}
|
||||
|
||||
// convert a bdecode_node into an old skool entry
|
||||
entry& entry::operator=(bdecode_node const& e)
|
||||
{
|
||||
|
@ -417,6 +451,17 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
entry& entry::operator=(preformatted_type const& v)
|
||||
{
|
||||
destruct();
|
||||
new(data) preformatted_type(v);
|
||||
m_type = preformatted_t;
|
||||
#ifdef TORRENT_DEBUG
|
||||
m_type_queried = true;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
entry& entry::operator=(dictionary_type const& v)
|
||||
{
|
||||
destruct();
|
||||
|
@ -475,6 +520,8 @@ namespace libtorrent
|
|||
return list() == e.list();
|
||||
case dictionary_t:
|
||||
return dict() == e.dict();
|
||||
case preformatted_t:
|
||||
return preformatted() == e.preformatted();
|
||||
default:
|
||||
TORRENT_ASSERT(m_type == undefined_t);
|
||||
return true;
|
||||
|
@ -499,6 +546,9 @@ namespace libtorrent
|
|||
break;
|
||||
case undefined_t:
|
||||
break;
|
||||
case preformatted_t:
|
||||
new (data) preformatted_type;
|
||||
break;
|
||||
}
|
||||
m_type = t;
|
||||
#ifdef TORRENT_DEBUG
|
||||
|
@ -524,6 +574,10 @@ namespace libtorrent
|
|||
break;
|
||||
case undefined_t:
|
||||
TORRENT_ASSERT(e.type() == undefined_t);
|
||||
break;
|
||||
case preformatted_t:
|
||||
new (data) preformatted_type(e.preformatted());
|
||||
break;
|
||||
}
|
||||
m_type = e.type();
|
||||
#ifdef TORRENT_DEBUG
|
||||
|
@ -547,6 +601,9 @@ namespace libtorrent
|
|||
case dictionary_t:
|
||||
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
||||
break;
|
||||
case preformatted_t:
|
||||
call_destructor(reinterpret_cast<preformatted_type*>(data));
|
||||
break;
|
||||
default:
|
||||
TORRENT_ASSERT(m_type == undefined_t);
|
||||
break;
|
||||
|
@ -597,6 +654,10 @@ namespace libtorrent
|
|||
std::swap(*reinterpret_cast<dictionary_type*>(data)
|
||||
, *reinterpret_cast<dictionary_type*>(e.data));
|
||||
break;
|
||||
case preformatted_t:
|
||||
std::swap(*reinterpret_cast<preformatted_type*>(data)
|
||||
, *reinterpret_cast<preformatted_type*>(e.data));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -689,6 +750,9 @@ namespace libtorrent
|
|||
i->second.to_string_impl(out, indent+2);
|
||||
}
|
||||
} break;
|
||||
case preformatted_t:
|
||||
out += "<preformatted>\n";
|
||||
break;
|
||||
case undefined_t:
|
||||
default:
|
||||
out += "<uninitialized>\n";
|
||||
|
|
|
@ -2038,19 +2038,76 @@ namespace aux {
|
|||
|
||||
if (m_socks_listen_socket) return;
|
||||
|
||||
m_socks_listen_socket = boost::shared_ptr<socket_type>(new socket_type(m_io_service));
|
||||
m_socks_listen_socket = boost::make_shared<socket_type>(boost::ref(m_io_service));
|
||||
bool const ret = instantiate_connection(m_io_service, proxy()
|
||||
, *m_socks_listen_socket, NULL, NULL, false, false);
|
||||
TORRENT_ASSERT_VAL(ret, ret);
|
||||
TORRENT_UNUSED(ret);
|
||||
|
||||
ADD_OUTSTANDING_ASYNC("session_impl::on_socks_accept");
|
||||
ADD_OUTSTANDING_ASYNC("session_impl::on_socks_listen");
|
||||
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
||||
s.set_command(2); // 2 means BIND (as opposed to CONNECT)
|
||||
m_socks_listen_port = 2000 + random() % 60000;
|
||||
|
||||
s.async_connect(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
||||
, boost::bind(&session_impl::on_socks_accept, this, m_socks_listen_socket, _1));
|
||||
m_socks_listen_port = listen_port();
|
||||
if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + random() % 60000;
|
||||
s.async_listen(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
||||
, boost::bind(&session_impl::on_socks_listen, this
|
||||
, m_socks_listen_socket, _1));
|
||||
}
|
||||
|
||||
void session_impl::on_socks_listen(boost::shared_ptr<socket_type> const& sock
|
||||
, error_code const& e)
|
||||
{
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
complete_async("session_impl::on_socks_listen");
|
||||
#endif
|
||||
|
||||
TORRENT_ASSERT(sock == m_socks_listen_socket || !m_socks_listen_socket);
|
||||
|
||||
if (e)
|
||||
{
|
||||
m_socks_listen_socket.reset();
|
||||
if (e == boost::asio::error::operation_aborted) return;
|
||||
if (m_alerts.should_post<listen_failed_alert>())
|
||||
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||
, tcp::endpoint(), listen_failed_alert::accept, e
|
||||
, listen_failed_alert::socks5);
|
||||
return;
|
||||
}
|
||||
|
||||
error_code ec;
|
||||
tcp::endpoint ep = sock->local_endpoint(ec);
|
||||
TORRENT_ASSERT(!ec);
|
||||
TORRENT_UNUSED(ec);
|
||||
|
||||
if (m_alerts.should_post<listen_succeeded_alert>())
|
||||
m_alerts.emplace_alert<listen_succeeded_alert>(
|
||||
ep, listen_succeeded_alert::socks5);
|
||||
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
add_outstanding_async("session_impl::on_socks_accept");
|
||||
#endif
|
||||
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
||||
s.async_accept(boost::bind(&session_impl::on_socks_accept, this
|
||||
, m_socks_listen_socket, _1));
|
||||
}
|
||||
|
||||
void session_impl::on_socks_accept(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e)
|
||||
{
|
||||
COMPLETE_ASYNC("session_impl::on_socks_accept");
|
||||
TORRENT_ASSERT(s == m_socks_listen_socket || !m_socks_listen_socket);
|
||||
m_socks_listen_socket.reset();
|
||||
if (e == boost::asio::error::operation_aborted) return;
|
||||
if (e)
|
||||
{
|
||||
if (m_alerts.should_post<listen_failed_alert>())
|
||||
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||
, tcp::endpoint(), listen_failed_alert::accept, e
|
||||
, listen_failed_alert::socks5);
|
||||
return;
|
||||
}
|
||||
open_new_incoming_socks_connection();
|
||||
incoming_connection(s);
|
||||
}
|
||||
|
||||
void session_impl::update_i2p_bridge()
|
||||
|
@ -2805,24 +2862,6 @@ namespace aux {
|
|||
set_socket_buffer_size(s, m_settings, ec);
|
||||
}
|
||||
|
||||
void session_impl::on_socks_accept(boost::shared_ptr<socket_type> const& s
|
||||
, error_code const& e)
|
||||
{
|
||||
COMPLETE_ASYNC("session_impl::on_socks_accept");
|
||||
m_socks_listen_socket.reset();
|
||||
if (e == boost::asio::error::operation_aborted) return;
|
||||
if (e)
|
||||
{
|
||||
if (m_alerts.should_post<listen_failed_alert>())
|
||||
m_alerts.emplace_alert<listen_failed_alert>("socks5"
|
||||
, tcp::endpoint(), listen_failed_alert::accept, e
|
||||
, listen_failed_alert::socks5);
|
||||
return;
|
||||
}
|
||||
open_new_incoming_socks_connection();
|
||||
incoming_connection(s);
|
||||
}
|
||||
|
||||
// if cancel_with_cq is set, the peer connection is
|
||||
// currently expected to be scheduled for a connection
|
||||
// with the connection queue, and should be cancelled
|
||||
|
@ -5245,7 +5284,7 @@ namespace aux {
|
|||
// proxy, and it's the same one as we're using for the tracker
|
||||
// just tell the tracker the socks5 port we're listening on
|
||||
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||
return m_socks_listen_port;
|
||||
return m_socks_listen_socket->local_endpoint().port();
|
||||
|
||||
// if not, don't tell the tracker anything if we're in force_proxy
|
||||
// mode. We don't want to leak our listen port since it can
|
||||
|
|
|
@ -79,6 +79,56 @@ namespace libtorrent
|
|||
return socks_category;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// parse out the endpoint from a SOCKS response
|
||||
tcp::endpoint parse_endpoint(std::vector<char> const& buffer
|
||||
, int const version)
|
||||
{
|
||||
using namespace libtorrent::detail;
|
||||
char const* p = &buffer[0];
|
||||
p += 2; // version & response code
|
||||
if (version == 5)
|
||||
{
|
||||
++p; // reserved byte
|
||||
int const atyp = read_uint8(p);
|
||||
|
||||
if (atyp == 1)
|
||||
{
|
||||
tcp::endpoint ret;
|
||||
ret.address(read_v4_address(p));
|
||||
ret.port(read_uint16(p));
|
||||
return ret;
|
||||
}
|
||||
else if (atyp == 3)
|
||||
{
|
||||
// we don't support resolving the endpoint address
|
||||
// if we receive a domain name, just set the remote
|
||||
// endpoint to INADDR_ANY
|
||||
return tcp::endpoint();
|
||||
}
|
||||
else if (atyp == 4)
|
||||
{
|
||||
tcp::endpoint ret;
|
||||
#if TORRENT_USE_IPV6
|
||||
ret.address(read_v6_address(p));
|
||||
ret.port(read_uint16(p));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (version == 4)
|
||||
{
|
||||
tcp::endpoint ret;
|
||||
ret.port(read_uint16(p));
|
||||
ret.address(read_v4_address(p));
|
||||
return ret;
|
||||
}
|
||||
TORRENT_ASSERT(false);
|
||||
return tcp::endpoint();
|
||||
}
|
||||
}
|
||||
|
||||
void socks5_stream::name_lookup(error_code const& e, tcp::resolver::iterator i
|
||||
, boost::shared_ptr<handler_type> h)
|
||||
{
|
||||
|
@ -322,10 +372,9 @@ namespace libtorrent
|
|||
|
||||
using namespace libtorrent::detail;
|
||||
|
||||
// send SOCKS5 connect command
|
||||
char* p = &m_buffer[0];
|
||||
int version = read_uint8(p);
|
||||
int response = read_uint8(p);
|
||||
char const* p = &m_buffer[0];
|
||||
int const version = read_uint8(p);
|
||||
int const response = read_uint8(p);
|
||||
|
||||
if (m_version == 5)
|
||||
{
|
||||
|
@ -351,21 +400,22 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
p += 1; // reserved
|
||||
int atyp = read_uint8(p);
|
||||
// we ignore the proxy IP it was bound to
|
||||
int const atyp = read_uint8(p);
|
||||
// read the proxy IP it was bound to (this is variable length depending
|
||||
// on address type)
|
||||
if (atyp == 1)
|
||||
{
|
||||
if (m_command == socks5_bind)
|
||||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
ADD_OUTSTANDING_ASYNC("socks5_stream::connect1");
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
connect1(e, h);
|
||||
return;
|
||||
}
|
||||
m_remote_endpoint.address(read_v4_address(p));
|
||||
m_remote_endpoint.port(read_uint16(p));
|
||||
else
|
||||
{
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
}
|
||||
|
@ -379,10 +429,12 @@ namespace libtorrent
|
|||
int extra_bytes = 0;
|
||||
if (atyp == 4)
|
||||
{
|
||||
// IPv6
|
||||
extra_bytes = 12;
|
||||
}
|
||||
else if (atyp == 3)
|
||||
{
|
||||
// hostname with length prefix
|
||||
extra_bytes = read_uint8(p) - 3;
|
||||
}
|
||||
else
|
||||
|
@ -412,13 +464,13 @@ namespace libtorrent
|
|||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
ADD_OUTSTANDING_ASYNC("socks5_stream::connect1");
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
connect1(e, h);
|
||||
return;
|
||||
}
|
||||
m_remote_endpoint.address(read_v4_address(p));
|
||||
m_remote_endpoint.port(read_uint16(p));
|
||||
else
|
||||
{
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
(*h)(e);
|
||||
}
|
||||
|
@ -452,27 +504,12 @@ namespace libtorrent
|
|||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
ADD_OUTSTANDING_ASYNC("socks5_stream::connect1");
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
connect1(e, h);
|
||||
return;
|
||||
}
|
||||
|
||||
char* p = &m_buffer[0];
|
||||
p += 2; // version and response code
|
||||
int atyp = read_uint8(p);
|
||||
TORRENT_ASSERT(atyp == 3 || atyp == 4);
|
||||
if (atyp == 4)
|
||||
else
|
||||
{
|
||||
// we don't support resolving the endpoint address
|
||||
// if we receive a domain name, just set the remote
|
||||
// endpoint to INADDR_ANY
|
||||
m_remote_endpoint = tcp::endpoint();
|
||||
}
|
||||
else if (atyp == 3)
|
||||
{
|
||||
m_remote_endpoint.address(read_v4_address(p));
|
||||
m_remote_endpoint.port(read_uint16(p));
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
|
|
|
@ -98,6 +98,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/aux_/file_progress.hpp"
|
||||
#include "libtorrent/alert_manager.hpp"
|
||||
#include "libtorrent/disk_interface.hpp"
|
||||
#include "libtorrent/broadcast_socket.hpp" // for is_ip_address
|
||||
// TODO: factor out cache_status to its own header
|
||||
#include "libtorrent/disk_io_thread.hpp" // for cache_status
|
||||
|
||||
|
@ -2944,7 +2945,7 @@ namespace libtorrent
|
|||
|
||||
// if we are aborting. we don't want any new peers
|
||||
req.num_want = (req.event == tracker_request::stopped)
|
||||
?0:settings().get_int(settings_pack::num_want);
|
||||
? 0 : settings().get_int(settings_pack::num_want);
|
||||
|
||||
time_point now = clock_type::now();
|
||||
|
||||
|
@ -4716,11 +4717,7 @@ namespace libtorrent
|
|||
update_want_tick();
|
||||
update_want_scrape();
|
||||
update_gauge();
|
||||
|
||||
// if the torrent is paused, it doesn't need
|
||||
// to announce with even=stopped again.
|
||||
if (!is_paused())
|
||||
stop_announcing();
|
||||
stop_announcing();
|
||||
|
||||
error_code ec;
|
||||
m_inactivity_timer.cancel(ec);
|
||||
|
@ -6326,7 +6323,10 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
bool proxy_hostnames = settings().get_bool(settings_pack::proxy_hostnames);
|
||||
bool const is_ip = is_ip_address(hostname.c_str());
|
||||
if (is_ip) a.address(address::from_string(hostname.c_str(), ec));
|
||||
bool const proxy_hostnames = settings().get_bool(settings_pack::proxy_hostnames)
|
||||
&& !is_ip;
|
||||
|
||||
if (proxy_hostnames
|
||||
&& (s->get<socks5_stream>()
|
||||
|
@ -6494,8 +6494,11 @@ namespace libtorrent
|
|||
if (valid_metadata())
|
||||
{
|
||||
if (m_magnet_link || (m_save_resume_flags & torrent_handle::save_info_dict))
|
||||
ret["info"] = bdecode(&torrent_file().metadata()[0]
|
||||
, &torrent_file().metadata()[0] + torrent_file().metadata_size());
|
||||
{
|
||||
boost::shared_array<char> const info = torrent_file().metadata();
|
||||
int const size = torrent_file().metadata_size();
|
||||
ret["info"].preformatted().assign(&info[0], &info[0] + size);
|
||||
}
|
||||
}
|
||||
|
||||
// blocks per piece
|
||||
|
@ -8284,7 +8287,7 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(want_peers_download() == m_links[aux::session_interface::torrent_want_peers_download].in_list());
|
||||
TORRENT_ASSERT(want_peers_finished() == m_links[aux::session_interface::torrent_want_peers_finished].in_list());
|
||||
TORRENT_ASSERT(want_tick() == m_links[aux::session_interface::torrent_want_tick].in_list());
|
||||
TORRENT_ASSERT((!m_allow_peers && m_auto_managed) == m_links[aux::session_interface::torrent_want_scrape].in_list());
|
||||
TORRENT_ASSERT((!m_allow_peers && m_auto_managed && !m_abort) == m_links[aux::session_interface::torrent_want_scrape].in_list());
|
||||
|
||||
bool is_checking = false;
|
||||
bool is_downloading = false;
|
||||
|
|
|
@ -1749,7 +1749,7 @@ private:
|
|||
// send_pkt() again)
|
||||
// returns true if there is more space for payload in our
|
||||
// congestion window, false if there is no more space.
|
||||
bool utp_socket_impl::send_pkt(int flags)
|
||||
bool utp_socket_impl::send_pkt(int const flags)
|
||||
{
|
||||
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
|
||||
INVARIANT_CHECK;
|
||||
|
@ -2028,7 +2028,7 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
|
||||
// for ST_DATA packets, payload size is 0. Such packets do not have unique
|
||||
// sequence numbers and should never be used as mtu probes
|
||||
if ((mtu_probe || p->mtu_probe) && payload_size > 0)
|
||||
if ((mtu_probe || p->mtu_probe) && payload_size > m_mtu_floor)
|
||||
{
|
||||
p->mtu_probe = true;
|
||||
m_mtu_seq = m_seq_nr;
|
||||
|
|
|
@ -112,6 +112,7 @@ feature.compose <launcher>valgrind : <testing.launcher>"valgrind --tool=memcheck
|
|||
test-suite libtorrent :
|
||||
[ run
|
||||
test_primitives.cpp
|
||||
test_create_torrent.cpp
|
||||
test_packet_buffer.cpp
|
||||
test_timestamp_history.cpp
|
||||
test_sha1_hash.cpp
|
||||
|
|
|
@ -27,6 +27,7 @@ test_programs = \
|
|||
test_torrent \
|
||||
test_tracker \
|
||||
test_transfer \
|
||||
test_create_torrent \
|
||||
enum_if \
|
||||
test_utp \
|
||||
test_session \
|
||||
|
@ -207,6 +208,7 @@ test_ssl_SOURCES = test_ssl.cpp
|
|||
test_torrent_SOURCES = test_torrent.cpp
|
||||
test_tracker_SOURCES = test_tracker.cpp
|
||||
test_transfer_SOURCES = test_transfer.cpp
|
||||
test_create_torrent_SOURCES = test_create_torrent.cpp
|
||||
enum_if_SOURCES = enum_if.cpp
|
||||
test_utp_SOURCES = test_utp.cpp
|
||||
test_session_SOURCES = test_session.cpp
|
||||
|
|
|
@ -80,7 +80,7 @@ private:
|
|||
char write_buf_proto[100];
|
||||
boost::uint32_t write_buffer[17*1024/4];
|
||||
boost::uint32_t buffer[17*1024/4];
|
||||
|
||||
|
||||
peer_mode_t m_mode;
|
||||
torrent_info const& m_ti;
|
||||
|
||||
|
|
|
@ -58,54 +58,72 @@ entry decode(std::string const& str)
|
|||
return bdecode(str.begin(), str.end());
|
||||
}
|
||||
|
||||
TORRENT_TEST(bencoding)
|
||||
TORRENT_TEST(strings)
|
||||
{
|
||||
// ** strings **
|
||||
{
|
||||
entry e("spam");
|
||||
TEST_CHECK(encode(e) == "4:spam");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
entry e("spam");
|
||||
TEST_CHECK(encode(e) == "4:spam");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** integers **
|
||||
{
|
||||
entry e(3);
|
||||
TEST_CHECK(encode(e) == "i3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers)
|
||||
{
|
||||
entry e(3);
|
||||
TEST_CHECK(encode(e) == "i3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
{
|
||||
entry e(-3);
|
||||
TEST_CHECK(encode(e) == "i-3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers2)
|
||||
{
|
||||
entry e(-3);
|
||||
TEST_CHECK(encode(e) == "i-3e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
{
|
||||
entry e(int(0));
|
||||
TEST_CHECK(encode(e) == "i0e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(integers3)
|
||||
{
|
||||
entry e(int(0));
|
||||
TEST_CHECK(encode(e) == "i0e");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** lists **
|
||||
{
|
||||
entry::list_type l;
|
||||
l.push_back(entry("spam"));
|
||||
l.push_back(entry("eggs"));
|
||||
entry e(l);
|
||||
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(lists)
|
||||
{
|
||||
entry::list_type l;
|
||||
l.push_back(entry("spam"));
|
||||
l.push_back(entry("eggs"));
|
||||
entry e(l);
|
||||
TEST_CHECK(encode(e) == "l4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
// ** dictionaries **
|
||||
{
|
||||
entry e(entry::dictionary_t);
|
||||
e["spam"] = entry("eggs");
|
||||
e["cow"] = entry("moo");
|
||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
TORRENT_TEST(dictionaries)
|
||||
{
|
||||
entry e(entry::dictionary_t);
|
||||
e["spam"] = entry("eggs");
|
||||
e["cow"] = entry("moo");
|
||||
TEST_CHECK(encode(e) == "d3:cow3:moo4:spam4:eggse");
|
||||
TEST_CHECK(decode(encode(e)) == e);
|
||||
}
|
||||
|
||||
TORRENT_TEST(preformatted)
|
||||
{
|
||||
entry e(entry::preformatted_t);
|
||||
char const str[] = "foobar";
|
||||
e.preformatted().assign(str, str + sizeof(str)-1);
|
||||
TEST_EQUAL(encode(e), "foobar");
|
||||
}
|
||||
|
||||
TORRENT_TEST(preformatted_node)
|
||||
{
|
||||
entry e(entry::dictionary_t);
|
||||
char const str[] = "foobar";
|
||||
e["info"] = entry::preformatted_type(str, str + sizeof(str)-1);
|
||||
TEST_EQUAL(encode(e), "d4:infofoobare");
|
||||
}
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
TORRENT_TEST(lazy_entry)
|
||||
{
|
||||
{
|
||||
char b[] = "i12453e";
|
||||
lazy_entry e;
|
||||
|
@ -609,8 +627,6 @@ TORRENT_TEST(bencoding)
|
|||
printf("%s\n", print_entry(e).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
}
|
||||
#endif // TORRENT_NO_DEPRECATE
|
||||
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 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 "test.hpp"
|
||||
|
||||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
#include "libtorrent/aux_/escape_string.hpp" // for convert_path_to_posix
|
||||
#include <boost/make_shared.hpp>
|
||||
#include <cstring>
|
||||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
// make sure creating a torrent from an existing handle preserves the
|
||||
// info-dictionary verbatim, so as to not alter the info-hash
|
||||
TORRENT_TEST(create_verbatim_torrent)
|
||||
{
|
||||
char const test_torrent[] = "d4:infod4:name6:foobar6:lengthi12345e12:piece lengthi65536e6:pieces20:ababababababababababee";
|
||||
|
||||
lt::torrent_info info(test_torrent, sizeof(test_torrent) - 1);
|
||||
|
||||
lt::create_torrent t(info);
|
||||
|
||||
std::vector<char> buffer;
|
||||
lt::bencode(std::back_inserter(buffer), t.generate());
|
||||
|
||||
// now, make sure the info dictionary was unchanged
|
||||
buffer.push_back('\0');
|
||||
char const* dest_info = std::strstr(&buffer[0], "4:info");
|
||||
|
||||
TEST_CHECK(dest_info != NULL);
|
||||
|
||||
// +1 and -2 here is to strip the outermost dictionary from the source
|
||||
// torrent, since create_torrent may have added items next to the info dict
|
||||
TEST_CHECK(memcmp(dest_info, test_torrent + 1, sizeof(test_torrent)-3) == 0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue