merged RC_1_1 into master
This commit is contained in:
commit
9696082355
|
@ -232,7 +232,7 @@ script:
|
|||
- if [[ "$cmake" == "1" ]]; then
|
||||
export CXX=g++-5 &&
|
||||
export CC=gcc-5 &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-Werror" -Dbuild_tests=ON -G "CodeBlocks - Unix Makefiles" .. &&
|
||||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-Werror" -Dbuild_tests=ON -Dbuild_examples=ON -G "CodeBlocks - Unix Makefiles" .. &&
|
||||
cmake --build . -- -j2;
|
||||
fi
|
||||
- cd ..
|
||||
|
|
|
@ -450,6 +450,19 @@ option(logging "build with logging" ON)
|
|||
option(build_tests "build tests" OFF)
|
||||
option(build_examples "build examples" OFF)
|
||||
|
||||
set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release FORCE)
|
||||
endif()
|
||||
|
||||
# add_definitions() doesn't seem to let you say wich build type to apply it to
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DTORRENT_DEBUG")
|
||||
if(UNIX)
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -g")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}")
|
||||
endif()
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
include_directories(${includes})
|
||||
|
@ -521,7 +534,10 @@ endif()
|
|||
|
||||
if (shared)
|
||||
add_library(torrent-rasterbar SHARED ${sources2})
|
||||
target_compile_definitions(torrent-rasterbar PRIVATE TORRENT_BUILDING_SHARED)
|
||||
target_compile_definitions(torrent-rasterbar
|
||||
PRIVATE TORRENT_BUILDING_SHARED
|
||||
INTERFACE TORRENT_LINKING_SHARED
|
||||
)
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden")
|
||||
|
@ -556,12 +572,6 @@ target_compile_definitions(torrent-rasterbar PUBLIC $<$<CONFIG:Debug>:TORRENT_DE
|
|||
|
||||
target_compile_definitions(torrent-rasterbar PRIVATE TORRENT_BUILDING_LIBRARY)
|
||||
|
||||
if (build_tests)
|
||||
# this will make some internal functions available in the
|
||||
# DLL interface, for the tests to access
|
||||
target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_EXPORT_EXTRA)
|
||||
endif (build_tests)
|
||||
|
||||
if (libiconv)
|
||||
find_package(Iconv REQUIRED)
|
||||
target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_USE_ICONV)
|
||||
|
@ -724,29 +734,8 @@ endif()
|
|||
|
||||
# === build tests ===
|
||||
if(build_tests)
|
||||
if (NOT logging)
|
||||
message(FATAL_ERROR "tests require logging to be enabled")
|
||||
endif()
|
||||
|
||||
file(GLOB tests RELATIVE "${PROJECT_SOURCE_DIR}" "test/test_*.cpp")
|
||||
list(REMOVE_ITEM tests "test/test_natpmp.cpp") # doesn't build at time of writing
|
||||
list(REMOVE_ITEM tests "test/test_utils.cpp") # helper file, not a test
|
||||
|
||||
add_library(test_common STATIC test/main.cpp test/test.cpp
|
||||
test/setup_transfer.cpp test/dht_server.cpp test/udp_tracker.cpp
|
||||
test/peer_server.cpp test/web_seed_suite.cpp test/swarm_suite.cpp
|
||||
test/test_utils.cpp test/make_torrent.hpp test/make_torrent.cpp
|
||||
test/settings.hpp test/settings.cpp)
|
||||
set_target_properties(test_common PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON)
|
||||
target_link_libraries(test_common torrent-rasterbar)
|
||||
enable_testing()
|
||||
|
||||
foreach(s ${tests})
|
||||
get_filename_component (sn ${s} NAME_WE)
|
||||
add_executable(${sn} ${s})
|
||||
target_link_libraries(${sn} test_common)
|
||||
set_target_properties(${sn} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/test")
|
||||
set_target_properties(${sn} PROPERTIES CXX_STANDARD 11 CXX_STANDARD_REQUIRED ON)
|
||||
add_test(NAME ${sn} COMMAND ${sn} WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/test")
|
||||
endforeach(s)
|
||||
# this will make some internal functions available in the DLL interface
|
||||
target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_EXPORT_EXTRA)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
|
|
@ -82,13 +82,14 @@
|
|||
* resume data no longer has timestamps of files
|
||||
* require C++11 to build libtorrent
|
||||
|
||||
* fix tie-break in duplicate peer connection disconnect logic
|
||||
* fix issue with SSL tracker connections left in CLOSE_WAIT state
|
||||
* defer truncating existing files until the first time we write to them
|
||||
* fix issue when receiving a torrent with 0-sized padfiles as magnet link
|
||||
* fix issue resuming 1.0.x downloads with a file priority 0
|
||||
* fix torrent_status::next_announce
|
||||
* fix pad-file scalability issue
|
||||
* made coalesce_reads/coalesce_writes settings take effect on linux and windows
|
||||
* restore support for incoming connections over SOCKS5 (disabled by default)
|
||||
* use unique peer_ids per connection
|
||||
* fix iOS build on recent SDK
|
||||
* fix tracker connection bind issue for IPv6 trackers
|
||||
|
|
|
@ -716,7 +716,7 @@ int save_file(std::string const& filename, std::vector<char> const& v)
|
|||
// returns true if the alert was handled (and should not be printed to the log)
|
||||
// returns false if the alert was not handled
|
||||
bool handle_alert(torrent_view& view, session_view& ses_view
|
||||
, lt::session& ses, lt::alert* a)
|
||||
, lt::session&, lt::alert* a)
|
||||
{
|
||||
using namespace lt;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ void print_alert(lt::alert const* a)
|
|||
std::printf("%s", "\x1b[0m");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
int main(int argc, char*[])
|
||||
{
|
||||
using namespace lt;
|
||||
|
||||
|
|
|
@ -341,10 +341,6 @@ namespace aux {
|
|||
void async_accept(std::shared_ptr<tcp::acceptor> const& listener, transport ssl);
|
||||
void on_accept_connection(std::shared_ptr<socket_type> const& s
|
||||
, std::weak_ptr<tcp::acceptor> listener, error_code const& e, transport ssl);
|
||||
void on_socks_listen(std::shared_ptr<socket_type> const& s
|
||||
, error_code const& e);
|
||||
void on_socks_accept(std::shared_ptr<socket_type> const& s
|
||||
, error_code const& e);
|
||||
|
||||
void incoming_connection(std::shared_ptr<socket_type> const& s);
|
||||
|
||||
|
@ -741,7 +737,6 @@ namespace aux {
|
|||
void update_listen_interfaces();
|
||||
void update_privileged_ports();
|
||||
void update_auto_sequential();
|
||||
void update_incoming_socks5();
|
||||
void update_max_failcount();
|
||||
void update_resolver_cache_timeout();
|
||||
|
||||
|
@ -950,16 +945,9 @@ namespace aux {
|
|||
void ssl_handshake(error_code const& ec, std::shared_ptr<socket_type> s);
|
||||
#endif
|
||||
|
||||
// when as a socks proxy is used for peers, also
|
||||
// listen for incoming connections on a socks connection
|
||||
std::shared_ptr<socket_type> m_socks_listen_socket;
|
||||
std::uint16_t m_socks_listen_port;
|
||||
|
||||
// round-robin index into m_outgoing_interfaces
|
||||
mutable std::uint8_t m_interface_index = 0;
|
||||
|
||||
void open_new_incoming_socks_connection();
|
||||
|
||||
std::shared_ptr<listen_socket_t> setup_listener(
|
||||
listen_endpoint_t const& lep, error_code& ec);
|
||||
|
||||
|
|
|
@ -727,12 +727,6 @@ namespace libtorrent {
|
|||
// changes are taken in consideration.
|
||||
enable_ip_notifier,
|
||||
|
||||
// this enables a SOCKS5 "extension", in which libtorrent attempts to
|
||||
// receive incoming connections over a SOCKS5 proxy. The traditional
|
||||
// interpretation of the RFC and normal SOCKS5 implementations do not
|
||||
// support this.
|
||||
incoming_socks5_connections,
|
||||
|
||||
max_bool_setting_internal
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ public:
|
|||
// commands
|
||||
enum {
|
||||
socks5_connect = 1,
|
||||
socks5_bind = 2,
|
||||
socks5_udp_associate = 3
|
||||
};
|
||||
|
||||
|
@ -93,7 +92,6 @@ public:
|
|||
: proxy_base(io_service)
|
||||
, m_version(5)
|
||||
, m_command(socks5_connect)
|
||||
, m_listen(0)
|
||||
{}
|
||||
|
||||
void set_version(int v) { m_version = v; }
|
||||
|
@ -111,38 +109,6 @@ 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;
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
add_outstanding_async("socks5_stream::connect1");
|
||||
#endif
|
||||
connect1(e, std::move(handler));
|
||||
}
|
||||
|
||||
template <typename Handler>
|
||||
void async_listen(tcp::endpoint const& ep, Handler const& handler)
|
||||
{
|
||||
m_command = socks5_bind;
|
||||
|
||||
m_remote_endpoint = ep;
|
||||
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
add_outstanding_async("socks5_stream::name_lookup");
|
||||
#endif
|
||||
tcp::resolver::query q(m_hostname, to_string(m_port).data());
|
||||
using std::placeholders::_1;
|
||||
using std::placeholders::_2;
|
||||
m_resolver.async_resolve(q, std::bind(
|
||||
&socks5_stream::name_lookup, this, _1, _2, handler_type(std::move(handler))));
|
||||
}
|
||||
|
||||
void set_dst_name(std::string const& host)
|
||||
{
|
||||
// if this assert trips, set_dst_name() is called wth an IP address rather
|
||||
|
@ -168,25 +134,12 @@ 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);
|
||||
TORRENT_ASSERT(endpoint.address() != address()
|
||||
|| (!m_dst_name.empty() && m_version == 5));
|
||||
|
||||
|
@ -230,19 +183,10 @@ private:
|
|||
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,
|
||||
// udp associate)
|
||||
// the socks command to send for this connection (connect or udp associate)
|
||||
int m_command;
|
||||
|
||||
// set to one when we're waiting for the
|
||||
// second message to accept an incoming connection
|
||||
int m_listen;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -138,7 +138,9 @@ private:
|
|||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
std::printf("fake_peer::connect() -> (%d) %s\n"
|
||||
asio::ip::tcp::endpoint const ep = m_socket.remote_endpoint();
|
||||
std::printf("fake_peer::connect(%s) -> (%d) %s\n"
|
||||
, lt::print_endpoint(ep).c_str()
|
||||
, ec.value(), ec.message().c_str());
|
||||
if (ec) return;
|
||||
|
||||
|
@ -150,7 +152,6 @@ private:
|
|||
memcpy(m_out_buffer, handshake, len);
|
||||
memcpy(&m_out_buffer[28], ih.data(), 20);
|
||||
|
||||
asio::ip::tcp::endpoint const ep = m_socket.remote_endpoint();
|
||||
asio::async_write(m_socket, asio::const_buffers_1(&m_out_buffer[0]
|
||||
, len), [this, ep](boost::system::error_code const& ec
|
||||
, size_t /* bytes_transferred */)
|
||||
|
|
|
@ -100,155 +100,6 @@ void run_test(Setup const& setup
|
|||
test(sim, *ses, params.ti);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_accept)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
bool incoming_connection = false;
|
||||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses.apply_settings(p);
|
||||
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
|
||||
, std::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)
|
||||
{
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses.apply_settings(p);
|
||||
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->endpoint.address(), addr("60.0.0.0"))
|
||||
incoming_connection = true;
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, std::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)
|
||||
{
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses.apply_settings(p);
|
||||
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->socket_type == socket_type_t::socks5)
|
||||
{
|
||||
TEST_EQUAL(a->address, addr("0.0.0.0"));
|
||||
TEST_EQUAL(a->port, 6881);
|
||||
listen_alert = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, std::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)
|
||||
{
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses.apply_settings(p);
|
||||
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->socket_type == socket_type_t::socks5)
|
||||
{
|
||||
TEST_EQUAL(a->address, addr("0.0.0.0"));
|
||||
TEST_EQUAL(a->port, 6881);
|
||||
listen_alert = true;
|
||||
}
|
||||
}
|
||||
},
|
||||
[](sim::simulation& sim, lt::session& ses
|
||||
, std::shared_ptr<lt::torrent_info> ti)
|
||||
{
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(listen_alert, true);
|
||||
}
|
||||
|
||||
TORRENT_TEST(socks5_tcp_announce)
|
||||
{
|
||||
using namespace lt;
|
||||
|
@ -257,9 +108,6 @@ TORRENT_TEST(socks5_tcp_announce)
|
|||
run_test(
|
||||
[](lt::session& ses)
|
||||
{
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses.apply_settings(p);
|
||||
set_proxy(ses, settings_pack::socks5);
|
||||
|
||||
lt::add_torrent_params params;
|
||||
|
@ -305,7 +153,8 @@ TORRENT_TEST(socks5_tcp_announce)
|
|||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(alert_port, tracker_port);
|
||||
// since force_proxy is enabled, don't send the port
|
||||
TEST_EQUAL(tracker_port, 0);
|
||||
TEST_CHECK(alert_port != -1);
|
||||
TEST_CHECK(tracker_port != -1);
|
||||
}
|
||||
|
|
|
@ -63,8 +63,6 @@ std::string make_ep_string(char const* address, bool const is_v6
|
|||
return ret;
|
||||
}
|
||||
|
||||
const int connect_socks = 2;
|
||||
|
||||
template <typename Setup, typename HandleAlerts, typename Test>
|
||||
void run_test(
|
||||
Setup const& setup
|
||||
|
@ -124,8 +122,7 @@ void run_test(
|
|||
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
|
||||
if (auto ta = alert_cast<lt::add_torrent_alert>(a))
|
||||
{
|
||||
ta->handle.connect_peer(lt::tcp::endpoint(
|
||||
(flags & connect_socks) ? proxy : peer1, 6881));
|
||||
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
|
||||
}
|
||||
on_alert(ses, a);
|
||||
});
|
||||
|
@ -191,29 +188,6 @@ TORRENT_TEST(socks5_tcp_connect)
|
|||
);
|
||||
}
|
||||
|
||||
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
|
||||
settings_pack p;
|
||||
p.set_bool(settings_pack::incoming_socks5_connections, true);
|
||||
ses1.apply_settings(p);
|
||||
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 lt;
|
||||
|
|
|
@ -3190,7 +3190,7 @@ namespace {
|
|||
// initiate connections. So, if our peer-id is greater than
|
||||
// the others, we should close the incoming connection,
|
||||
// if not, we should close the outgoing one.
|
||||
if (pid < m_our_peer_id && is_outgoing())
|
||||
if ((pid < m_our_peer_id) == is_outgoing())
|
||||
{
|
||||
p->disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
}
|
||||
|
|
|
@ -636,7 +636,7 @@ namespace libtorrent {
|
|||
|
||||
if (i->connection != nullptr)
|
||||
{
|
||||
bool self_connection =
|
||||
bool const self_connection =
|
||||
i->connection->remote() == c.local_endpoint()
|
||||
|| i->connection->local_endpoint() == c.remote();
|
||||
|
||||
|
@ -667,63 +667,44 @@ namespace libtorrent {
|
|||
// disconnect the same one, we need a consistent rule to
|
||||
// select which one.
|
||||
|
||||
bool outgoing1 = c.is_outgoing();
|
||||
bool const outgoing1 = c.is_outgoing();
|
||||
|
||||
// for this, we compare our endpoints (IP and port)
|
||||
// and whoever has the lower IP,port should be the
|
||||
// one keeping its outgoing connection. Since outgoing
|
||||
// ports are selected at random by the OS, we need
|
||||
// to be careful to only look at the target end of a
|
||||
// connection for the endpoint.
|
||||
// for this, we compare our ports and whoever has the lower port
|
||||
// should be the one keeping its outgoing connection. Since
|
||||
// outgoing ports are selected at random by the OS, we need to
|
||||
// be careful to only look at the target end of a connection for
|
||||
// the endpoint.
|
||||
|
||||
int our_port = outgoing1 ? i->connection->local_endpoint().port() : c.local_endpoint().port();
|
||||
int other_port= outgoing1 ? c.remote().port() : i->connection->remote().port();
|
||||
int const our_port = outgoing1 ? i->connection->local_endpoint().port() : c.local_endpoint().port();
|
||||
int const other_port = outgoing1 ? c.remote().port() : i->connection->remote().port();
|
||||
|
||||
// decide which peer connection to disconnect
|
||||
// if the ports are equal, pick on at random
|
||||
bool const disconnect1 = ((our_port < other_port) && !outgoing1)
|
||||
|| ((our_port > other_port) && outgoing1)
|
||||
|| ((our_port == other_port) && random(1));
|
||||
|
||||
if (our_port < other_port)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
if (c.should_log(peer_log_alert::info))
|
||||
{
|
||||
c.peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "\"%d\" < \"%d\"", our_port, other_port);
|
||||
i->connection->peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "\"%d\" < \"%d\"", our_port, other_port);
|
||||
}
|
||||
if (c.should_log(peer_log_alert::info))
|
||||
{
|
||||
c.peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "our: %d other: %d disconnecting: %s"
|
||||
, our_port, other_port, disconnect1 ? "yes" : "no");
|
||||
i->connection->peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "our: %d other: %d disconnecting: %s"
|
||||
, our_port, other_port, disconnect1 ? "no" : "yes");
|
||||
}
|
||||
#endif
|
||||
|
||||
// we should keep our outgoing connection
|
||||
if (!outgoing1)
|
||||
{
|
||||
c.disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
return false;
|
||||
}
|
||||
TORRENT_ASSERT(m_locked_peer == nullptr);
|
||||
m_locked_peer = i;
|
||||
i->connection->disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
m_locked_peer = nullptr;
|
||||
}
|
||||
else
|
||||
if (disconnect1)
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
if (c.should_log(peer_log_alert::info))
|
||||
{
|
||||
c.peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "\"%d\" >= \"%d\"", our_port, other_port);
|
||||
i->connection->peer_log(peer_log_alert::info, "DUPLICATE_PEER_RESOLUTION"
|
||||
, "\"%d\" >= \"%d\"", our_port, other_port);
|
||||
}
|
||||
#endif
|
||||
// they should keep their outgoing connection
|
||||
if (outgoing1)
|
||||
{
|
||||
c.disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
return false;
|
||||
}
|
||||
TORRENT_ASSERT(m_locked_peer == nullptr);
|
||||
m_locked_peer = i;
|
||||
i->connection->disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
m_locked_peer = nullptr;
|
||||
c.disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
return false;
|
||||
}
|
||||
TORRENT_ASSERT(m_locked_peer == nullptr);
|
||||
m_locked_peer = i;
|
||||
i->connection->disconnect(errors::duplicate_peer_id, operation_t::bittorrent);
|
||||
m_locked_peer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ namespace libtorrent { namespace aux {
|
|||
}
|
||||
}
|
||||
|
||||
std::uint32_t random(std::uint32_t max)
|
||||
std::uint32_t random(std::uint32_t const max)
|
||||
{
|
||||
return std::uniform_int_distribution<std::uint32_t>(0, max)(aux::random_engine());
|
||||
}
|
||||
|
|
|
@ -420,7 +420,6 @@ namespace aux {
|
|||
#if TORRENT_USE_I2P
|
||||
, m_i2p_conn(m_io_service)
|
||||
#endif
|
||||
, m_socks_listen_port(0)
|
||||
, m_created(clock_type::now())
|
||||
, m_last_tick(m_created)
|
||||
, m_last_second_tick(m_created - milliseconds(900))
|
||||
|
@ -910,13 +909,6 @@ namespace aux {
|
|||
|
||||
m_outgoing_sockets.close();
|
||||
|
||||
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||
{
|
||||
m_socks_listen_socket->close(ec);
|
||||
TORRENT_ASSERT(!ec);
|
||||
}
|
||||
m_socks_listen_socket.reset();
|
||||
|
||||
// we need to give all the sockets an opportunity to actually have their handlers
|
||||
// called and cancelled before we continue the shutdown. This is a bit
|
||||
// complicated, if there are no "undead" peers, it's safe to resume the
|
||||
|
@ -1940,7 +1932,6 @@ namespace aux {
|
|||
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
||||
}
|
||||
|
||||
open_new_incoming_socks_connection();
|
||||
#if TORRENT_USE_I2P
|
||||
open_new_incoming_i2p_connection();
|
||||
#endif
|
||||
|
@ -2134,99 +2125,6 @@ namespace aux {
|
|||
}
|
||||
}
|
||||
|
||||
void session_impl::open_new_incoming_socks_connection()
|
||||
{
|
||||
int const proxy_type = m_settings.get_int(settings_pack::proxy_type);
|
||||
|
||||
if (proxy_type != settings_pack::socks5
|
||||
&& proxy_type != settings_pack::socks5_pw
|
||||
&& proxy_type != settings_pack::socks4)
|
||||
return;
|
||||
|
||||
if (!m_settings.get_bool(settings_pack::incoming_socks5_connections))
|
||||
return;
|
||||
|
||||
if (m_socks_listen_socket) return;
|
||||
|
||||
m_socks_listen_socket = std::make_shared<socket_type>(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);
|
||||
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
add_outstanding_async("session_impl::on_socks_listen");
|
||||
#endif
|
||||
socks5_stream& s = *m_socks_listen_socket->get<socks5_stream>();
|
||||
|
||||
m_socks_listen_port = m_listen_interfaces.empty() ? 0
|
||||
: static_cast<std::uint16_t>(m_listen_interfaces[0].port);
|
||||
if (m_socks_listen_port == 0) m_socks_listen_port = static_cast<std::uint16_t>(2000 + random(60000));
|
||||
s.async_listen(tcp::endpoint(address_v4::any(), m_socks_listen_port)
|
||||
, std::bind(&session_impl::on_socks_listen, this
|
||||
, m_socks_listen_socket, _1));
|
||||
}
|
||||
|
||||
void session_impl::on_socks_listen(std::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(), operation_t::sock_accept, e
|
||||
, socket_type_t::socks5);
|
||||
return;
|
||||
}
|
||||
|
||||
error_code ec;
|
||||
tcp::endpoint const ep = sock->local_endpoint(ec);
|
||||
TORRENT_ASSERT(!ec);
|
||||
TORRENT_UNUSED(ec);
|
||||
|
||||
m_socks_listen_port = ep.port();
|
||||
|
||||
if (m_alerts.should_post<listen_succeeded_alert>())
|
||||
m_alerts.emplace_alert<listen_succeeded_alert>(
|
||||
ep, socket_type_t::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(std::bind(&session_impl::on_socks_accept, this
|
||||
, m_socks_listen_socket, _1));
|
||||
}
|
||||
|
||||
void session_impl::on_socks_accept(std::shared_ptr<socket_type> const& s
|
||||
, error_code const& e)
|
||||
{
|
||||
#if defined TORRENT_ASIO_DEBUGGING
|
||||
complete_async("session_impl::on_socks_accept");
|
||||
#endif
|
||||
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(), operation_t::sock_accept, e
|
||||
, socket_type_t::socks5);
|
||||
return;
|
||||
}
|
||||
open_new_incoming_socks_connection();
|
||||
incoming_connection(s);
|
||||
}
|
||||
|
||||
void session_impl::update_i2p_bridge()
|
||||
{
|
||||
// we need this socket to be open before we
|
||||
|
@ -5350,22 +5248,6 @@ namespace aux {
|
|||
i.second->update_auto_sequential();
|
||||
}
|
||||
|
||||
void session_impl::update_incoming_socks5()
|
||||
{
|
||||
if (!m_settings.get_bool(settings_pack::incoming_socks5_connections))
|
||||
{
|
||||
if (m_socks_listen_socket)
|
||||
{
|
||||
m_socks_listen_socket->close();
|
||||
m_socks_listen_socket.reset();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
open_new_incoming_socks_connection();
|
||||
}
|
||||
}
|
||||
|
||||
void session_impl::update_max_failcount()
|
||||
{
|
||||
for (auto& i : m_torrents)
|
||||
|
@ -5380,9 +5262,6 @@ namespace aux {
|
|||
|
||||
void session_impl::update_proxy()
|
||||
{
|
||||
// in case we just set a socks proxy, we might have to
|
||||
// open the socks incoming connection
|
||||
if (!m_socks_listen_socket) open_new_incoming_socks_connection();
|
||||
for (auto& i : m_listen_sockets)
|
||||
i->udp_sock->sock.set_proxy_settings(proxy());
|
||||
m_outgoing_sockets.update_proxy(proxy());
|
||||
|
@ -5466,13 +5345,6 @@ namespace aux {
|
|||
|
||||
std::uint16_t session_impl::listen_port(listen_socket_t* sock) const
|
||||
{
|
||||
// if peer connections are set up to be received over a socks
|
||||
// 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
|
||||
// TODO: socks5 proxies should be treated as a separate interface!
|
||||
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||
return m_socks_listen_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
|
||||
// potentially identify us if it is leaked elsewhere
|
||||
|
@ -5492,13 +5364,6 @@ namespace aux {
|
|||
std::uint16_t session_impl::ssl_listen_port(listen_socket_t* sock) const
|
||||
{
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
// if peer connections are set up to be received over a socks
|
||||
// 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
|
||||
// TODO: socks5 proxies should be treated as a separate interface!
|
||||
if (m_socks_listen_socket && m_socks_listen_socket->is_open())
|
||||
return m_socks_listen_port;
|
||||
|
||||
if (sock) return std::uint16_t(sock->tcp_external_port);
|
||||
|
||||
// if not, don't tell the tracker anything if we're in force_proxy
|
||||
|
|
|
@ -200,7 +200,6 @@ constexpr int CLOSE_FILE_INTERVAL = 0;
|
|||
SET(auto_sequential, true, &session_impl::update_auto_sequential),
|
||||
SET(proxy_tracker_connections, true, nullptr),
|
||||
SET(enable_ip_notifier, true, &session_impl::update_ip_notifier),
|
||||
SET(incoming_socks5_connections, false, &session_impl::update_incoming_socks5),
|
||||
}});
|
||||
|
||||
aux::array<int_setting_entry_t, settings_pack::num_int_settings> const int_settings
|
||||
|
|
|
@ -141,6 +141,8 @@ namespace aux {
|
|||
#ifdef TORRENT_USE_OPENSSL
|
||||
namespace {
|
||||
|
||||
void nop(std::shared_ptr<void>) {}
|
||||
|
||||
void on_close_socket(socket_type* s, std::shared_ptr<void>)
|
||||
{
|
||||
COMPLETE_ASYNC("on_close_socket");
|
||||
|
@ -165,9 +167,16 @@ namespace aux {
|
|||
#define MAYBE_ASIO_DEBUGGING
|
||||
#endif
|
||||
|
||||
char const buffer[] = "";
|
||||
// chasing the async_shutdown by a write is a trick to close the socket as
|
||||
// soon as we've sent the close_notify, without having to wait to receive a
|
||||
// response from the other end
|
||||
// https://stackoverflow.com/questions/32046034/what-is-the-proper-way-to-securely-disconnect-an-asio-ssl-socket
|
||||
|
||||
#define CASE(t) case socket_type_int_impl<ssl_stream<t>>::value: \
|
||||
MAYBE_ASIO_DEBUGGING \
|
||||
s.get<ssl_stream<t>>()->async_shutdown(std::bind(&on_close_socket, &s, holder)); \
|
||||
s.get<ssl_stream<t>>()->async_shutdown(std::bind(&nop, holder)); \
|
||||
s.get<ssl_stream<t>>()->async_write_some(boost::asio::buffer(buffer), std::bind(&on_close_socket, &s, holder)); \
|
||||
break;
|
||||
|
||||
switch (s.type())
|
||||
|
|
|
@ -77,56 +77,6 @@ namespace libtorrent {
|
|||
return cat;
|
||||
}
|
||||
|
||||
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
|
||||
, handler_type h)
|
||||
{
|
||||
|
@ -298,7 +248,7 @@ namespace libtorrent {
|
|||
:(m_remote_endpoint.address().is_v4()?4:16)));
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(5, p); // SOCKS VERSION 5
|
||||
write_uint8(std::uint8_t(m_command), p); // CONNECT/BIND command
|
||||
write_uint8(std::uint8_t(m_command), p); // CONNECT command
|
||||
write_uint8(0, p); // reserved
|
||||
if (!m_dst_name.empty())
|
||||
{
|
||||
|
@ -311,8 +261,7 @@ namespace libtorrent {
|
|||
else
|
||||
{
|
||||
// we either need a hostname or a valid endpoint
|
||||
TORRENT_ASSERT(m_command == socks5_bind
|
||||
|| m_remote_endpoint.address() != address());
|
||||
TORRENT_ASSERT(m_remote_endpoint.address() != address());
|
||||
|
||||
write_uint8(m_remote_endpoint.address().is_v4()?1:4, p); // address type
|
||||
write_address(m_remote_endpoint.address(), p);
|
||||
|
@ -330,7 +279,7 @@ namespace libtorrent {
|
|||
m_buffer.resize(m_user.size() + 9);
|
||||
char* p = &m_buffer[0];
|
||||
write_uint8(4, p); // SOCKS VERSION 4
|
||||
write_uint8(std::uint8_t(m_command), p); // CONNECT/BIND command
|
||||
write_uint8(std::uint8_t(m_command), p); // CONNECT command
|
||||
write_uint16(m_remote_endpoint.port(), p);
|
||||
write_uint32(m_remote_endpoint.address().to_v4().to_ulong(), p);
|
||||
std::copy(m_user.begin(), m_user.end(), p);
|
||||
|
@ -403,18 +352,6 @@ namespace libtorrent {
|
|||
// on address type)
|
||||
if (atyp == 1)
|
||||
{
|
||||
if (m_command == socks5_bind)
|
||||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
h(e);
|
||||
return;
|
||||
|
@ -453,18 +390,6 @@ namespace libtorrent {
|
|||
// access granted
|
||||
if (response == 90)
|
||||
{
|
||||
if (m_command == socks5_bind)
|
||||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
h(e);
|
||||
return;
|
||||
|
@ -488,18 +413,6 @@ namespace libtorrent {
|
|||
|
||||
if (handle_error(e, h)) return;
|
||||
|
||||
if (m_command == socks5_bind)
|
||||
{
|
||||
if (m_listen == 0)
|
||||
{
|
||||
m_local_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
m_listen = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_remote_endpoint = parse_endpoint(m_buffer, m_version);
|
||||
}
|
||||
}
|
||||
std::vector<char>().swap(m_buffer);
|
||||
h(e);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
cmake_minimum_required(VERSION 2.6)
|
||||
|
||||
file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/test_*.cpp")
|
||||
list(REMOVE_ITEM tests "${CMAKE_CURRENT_SOURCE_DIR}/test_natpmp.cpp") # doesn't build at time of writing
|
||||
list(REMOVE_ITEM tests "${CMAKE_CURRENT_SOURCE_DIR}/test_utils.cpp") # helper file, not a test
|
||||
|
||||
add_library(test_common OBJECT main.cpp test.cpp setup_transfer.cpp dht_server.cpp udp_tracker.cpp
|
||||
peer_server.cpp web_seed_suite.cpp swarm_suite.cpp test_utils.cpp make_torrent.cpp settings.cpp
|
||||
)
|
||||
target_compile_definitions(test_common PRIVATE $<TARGET_PROPERTY:torrent-rasterbar,INTERFACE_COMPILE_DEFINITIONS>)
|
||||
target_compile_features(test_common PUBLIC cxx_std_11)
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET test_common PROPERTY COMPILE_PDB_NAME "${CMAKE_CURRENT_BINARY_DIR}/test_common")
|
||||
endif()
|
||||
|
||||
foreach(TARGET_SRC ${tests})
|
||||
get_filename_component(TARGET ${TARGET_SRC} NAME_WE)
|
||||
add_executable(${TARGET} ${TARGET_SRC} $<TARGET_OBJECTS:test_common>)
|
||||
target_compile_features(${TARGET} PRIVATE cxx_std_11)
|
||||
target_link_libraries(${TARGET} torrent-rasterbar)
|
||||
add_test(${TARGET} ${TARGET})
|
||||
endforeach()
|
||||
|
||||
file(GLOB GZIP_ASSETS "${CMAKE_CURRENT_SOURCE_DIR}/*.gz")
|
||||
file(COPY ${GZIP_ASSETS} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
file(GLOB PYTHON_ASSETS "${CMAKE_CURRENT_SOURCE_DIR}/*.py")
|
||||
file(COPY ${PYTHON_ASSETS} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
file(GLOB XML_ASSETS "${CMAKE_CURRENT_SOURCE_DIR}/*.xml")
|
||||
file(COPY ${XML_ASSETS} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
file(COPY "utf8_test.txt" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "mutable_test_torrents" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "test_torrents" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
file(COPY "ssl" DESTINATION "${CMAKE_CURRENT_BINARY_DIR}")
|
|
@ -178,7 +178,7 @@ alert const* wait_for_alert(lt::session& ses, int type, char const* name
|
|||
static std::map<lt::session*, std::vector<alert*>> cache;
|
||||
auto& alerts = cache[&ses];
|
||||
|
||||
time_point end_time = lt::clock_type::now() + seconds(10);
|
||||
time_point const end_time = lt::clock_type::now() + seconds(10);
|
||||
while (true)
|
||||
{
|
||||
time_point now = clock_type::now();
|
||||
|
@ -277,21 +277,26 @@ bool print_alerts(lt::session& ses, char const* name
|
|||
, bool allow_no_torrents, bool allow_failed_fastresume
|
||||
, std::function<bool(lt::alert const*)> predicate, bool no_output)
|
||||
{
|
||||
bool ret = false;
|
||||
std::vector<torrent_handle> handles = ses.get_torrents();
|
||||
TEST_CHECK(!handles.empty() || allow_no_torrents);
|
||||
torrent_handle h;
|
||||
if (!handles.empty()) h = handles[0];
|
||||
TEST_CHECK(!ses.get_torrents().empty() || allow_no_torrents);
|
||||
std::vector<alert*> alerts;
|
||||
ses.pop_alerts(&alerts);
|
||||
for (auto a : alerts)
|
||||
{
|
||||
if (predicate && predicate(a)) ret = true;
|
||||
if (peer_disconnected_alert const* p = alert_cast<peer_disconnected_alert>(a))
|
||||
{
|
||||
std::printf("%s: %s: [%s] (%s): %s\n", time_now_string(), name, a->what()
|
||||
, print_endpoint(p->endpoint).c_str(), p->message().c_str());
|
||||
}
|
||||
else if (a->type() == invalid_request_alert::alert_type)
|
||||
{
|
||||
fprintf(stdout, "peer error: %s\n", a->message().c_str());
|
||||
TEST_CHECK(false);
|
||||
}
|
||||
else if (a->type() == fastresume_rejected_alert::alert_type)
|
||||
{
|
||||
fprintf(stdout, "resume data error: %s\n", a->message().c_str());
|
||||
TEST_CHECK(allow_failed_fastresume);
|
||||
}
|
||||
else if (should_print(a) && !no_output)
|
||||
{
|
||||
std::printf("%s: %s: [%s] %s\n", time_now_string(), name, a->what(), a->message().c_str());
|
||||
|
@ -306,7 +311,7 @@ bool print_alerts(lt::session& ses, char const* name
|
|||
TEST_CHECK(false);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
return predicate && std::any_of(alerts.begin(), alerts.end(), predicate);
|
||||
}
|
||||
|
||||
void wait_for_listen(lt::session& ses, char const* name)
|
||||
|
@ -315,15 +320,9 @@ void wait_for_listen(lt::session& ses, char const* name)
|
|||
alert const* a = nullptr;
|
||||
do
|
||||
{
|
||||
print_alerts(ses, name, true, true, [&listen_done](lt::alert const* al)
|
||||
{
|
||||
if (alert_cast<listen_failed_alert>(al)
|
||||
|| alert_cast<listen_succeeded_alert>(al))
|
||||
{
|
||||
listen_done = true;
|
||||
}
|
||||
return true;
|
||||
}, false);
|
||||
listen_done = print_alerts(ses, name, true, true, [&listen_done](lt::alert const* al)
|
||||
{ return alert_cast<listen_failed_alert>(al) || alert_cast<listen_succeeded_alert>(al); }
|
||||
, false);
|
||||
if (listen_done) break;
|
||||
a = ses.wait_for_alert(milliseconds(500));
|
||||
} while (a);
|
||||
|
@ -338,12 +337,11 @@ void wait_for_downloading(lt::session& ses, char const* name)
|
|||
alert const* a = nullptr;
|
||||
do
|
||||
{
|
||||
print_alerts(ses, name, true, true, [&downloading_done](lt::alert const* al)
|
||||
downloading_done = print_alerts(ses, name, true, true
|
||||
, [&downloading_done](lt::alert const* al)
|
||||
{
|
||||
state_changed_alert const* sc = alert_cast<state_changed_alert>(al);
|
||||
if (sc && sc->state == torrent_status::downloading)
|
||||
downloading_done = true;
|
||||
return true;
|
||||
return sc && sc->state == torrent_status::downloading;
|
||||
}, false);
|
||||
if (downloading_done) break;
|
||||
if (total_seconds(clock_type::now() - start) > 10) break;
|
||||
|
@ -398,24 +396,6 @@ typedef DWORD pid_type;
|
|||
typedef pid_t pid_type;
|
||||
#endif
|
||||
|
||||
struct proxy_t
|
||||
{
|
||||
pid_type pid;
|
||||
int type;
|
||||
};
|
||||
|
||||
// maps port to proxy type
|
||||
static std::map<int, proxy_t> running_proxies;
|
||||
|
||||
void stop_proxy(int port)
|
||||
{
|
||||
std::printf("stopping proxy on port %d\n", port);
|
||||
// don't shut down proxies until the test is
|
||||
// completely done. This saves a lot of time.
|
||||
// they're closed at the end of main() by
|
||||
// calling stop_all_proxies().
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// returns 0 on failure, otherwise pid
|
||||
|
@ -475,7 +455,9 @@ void stop_process(pid_type p)
|
|||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE proc = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE, FALSE, p);
|
||||
if (proc == NULL) return;
|
||||
TerminateProcess(proc, 138);
|
||||
WaitForSingleObject(proc, 5000);
|
||||
CloseHandle(proc);
|
||||
#else
|
||||
std::printf("killing pid: %d\n", p);
|
||||
|
@ -485,14 +467,34 @@ void stop_process(pid_type p)
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
struct proxy_t
|
||||
{
|
||||
pid_type pid;
|
||||
int type;
|
||||
};
|
||||
|
||||
// maps port to proxy type
|
||||
static std::map<int, proxy_t> running_proxies;
|
||||
|
||||
void stop_proxy(int port)
|
||||
{
|
||||
auto const it = running_proxies.find(port);
|
||||
|
||||
if (it == running_proxies.end()) return;
|
||||
|
||||
std::printf("stopping proxy on port %d\n", port);
|
||||
|
||||
stop_process(it->second.pid);
|
||||
running_proxies.erase(it);
|
||||
}
|
||||
|
||||
void stop_all_proxies()
|
||||
{
|
||||
std::map<int, proxy_t> proxies = running_proxies;
|
||||
for (std::map<int, proxy_t>::iterator i = proxies.begin()
|
||||
, end(proxies.end()); i != end; ++i)
|
||||
running_proxies.clear();
|
||||
for (auto const& i : proxies)
|
||||
{
|
||||
stop_process(i->second.pid);
|
||||
running_proxies.erase(i->second.pid);
|
||||
stop_process(i.second.pid);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -287,11 +287,7 @@ TORRENT_TEST(file)
|
|||
{
|
||||
error_code ec;
|
||||
file f;
|
||||
#if TORRENT_USE_UNC_PATHS || !defined _WIN32
|
||||
TEST_CHECK(f.open("con", open_mode::read_write, ec));
|
||||
#else
|
||||
TEST_CHECK(f.open("test_file", open_mode::read_write, ec));
|
||||
#endif
|
||||
if (ec)
|
||||
std::printf("open failed: [%s] %s\n", ec.category().name(), ec.message().c_str());
|
||||
TEST_EQUAL(ec, error_code());
|
||||
|
@ -408,6 +404,7 @@ TORRENT_TEST(stat_file)
|
|||
// specificaly UNC tests
|
||||
#if TORRENT_USE_UNC_PATHS
|
||||
|
||||
namespace {
|
||||
std::tuple<int, bool> fill_current_directory_caps()
|
||||
{
|
||||
#ifdef TORRENT_WINDOWS
|
||||
|
@ -428,9 +425,11 @@ std::tuple<int, bool> fill_current_directory_caps()
|
|||
return std::make_tuple(TORRENT_MAX_PATH, true);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TORRENT_TEST(unc_tests)
|
||||
{
|
||||
using lt::canonicalize_path;
|
||||
TEST_EQUAL(canonicalize_path("c:\\a\\..\\b"), "c:\\b");
|
||||
TEST_EQUAL(canonicalize_path("a\\..\\b"), "b");
|
||||
TEST_EQUAL(canonicalize_path("a\\..\\.\\b"), "b");
|
||||
|
@ -466,7 +465,7 @@ TORRENT_TEST(unc_tests)
|
|||
if (maximum_component_length > 0)
|
||||
{
|
||||
std::string long_component_name;
|
||||
long_component_name.resize(maximum_component_length);
|
||||
long_component_name.resize(size_t(maximum_component_length));
|
||||
for (int i = 0; i < maximum_component_length; ++i)
|
||||
long_component_name[i] = static_cast<char>((i % 26) + 'A');
|
||||
|
||||
|
@ -519,4 +518,15 @@ TORRENT_TEST(unc_tests)
|
|||
}
|
||||
}
|
||||
|
||||
TORRENT_TEST(unc_paths)
|
||||
{
|
||||
std::string const reserved_name = "con";
|
||||
error_code ec;
|
||||
{
|
||||
file f;
|
||||
TEST_CHECK(f.open(reserved_name, open_mode::read_write, ec) && !ec);
|
||||
}
|
||||
remove(reserved_name, ec);
|
||||
TEST_CHECK(!ec);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -59,14 +59,14 @@ void test_lsd()
|
|||
pack.set_bool(settings_pack::enable_lsd, true);
|
||||
pack.set_bool(settings_pack::enable_upnp, false);
|
||||
pack.set_bool(settings_pack::enable_natpmp, false);
|
||||
pack.set_str(settings_pack::listen_interfaces, "127.0.0.1:48100");
|
||||
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:48100");
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
pack.set_bool(settings_pack::rate_limit_utp, true);
|
||||
#endif
|
||||
|
||||
lt::session ses1(pack);
|
||||
|
||||
pack.set_str(settings_pack::listen_interfaces, "127.0.0.1:49100");
|
||||
pack.set_str(settings_pack::listen_interfaces, "0.0.0.0:49100");
|
||||
lt::session ses2(pack);
|
||||
|
||||
torrent_handle tor1;
|
||||
|
|
|
@ -812,6 +812,43 @@ TORRENT_TEST(double_connection_loose)
|
|||
TEST_EQUAL(con_in->was_disconnected(), false);
|
||||
}
|
||||
|
||||
// test double connection with identical ports (random)
|
||||
TORRENT_TEST(double_connection_random)
|
||||
{
|
||||
int in = 0;
|
||||
int out = 0;
|
||||
for (int i = 0; i < 30; ++i)
|
||||
{
|
||||
torrent_state st = init_state();
|
||||
mock_torrent t(&st);
|
||||
st.allow_multiple_connections_per_ip = false;
|
||||
peer_list p(allocator);
|
||||
t.m_p = &p;
|
||||
|
||||
// we are 10.0.0.1 and the other peer is 10.0.0.2
|
||||
|
||||
// our outgoing connection
|
||||
torrent_peer* peer = add_peer(p, st, ep("10.0.0.2", 3000));
|
||||
connect_peer(p, t, st);
|
||||
|
||||
auto con_out = static_cast<mock_peer_connection*>(peer->connection)->shared_from_this();
|
||||
con_out->set_local_ep(ep("10.0.0.1", 3000));
|
||||
|
||||
// and the incoming connection
|
||||
auto con_in = std::make_shared<mock_peer_connection>(&t, false, ep("10.0.0.2", 3000));
|
||||
con_in->set_local_ep(ep("10.0.0.1", 3000));
|
||||
|
||||
p.new_connection(*con_in, 0, &st);
|
||||
|
||||
// the rules are documented in peer_list.cpp
|
||||
out += con_out->was_disconnected();
|
||||
in += con_in->was_disconnected();
|
||||
}
|
||||
// we should have gone different ways randomly
|
||||
TEST_CHECK(out > 0);
|
||||
TEST_CHECK(in > 0);
|
||||
}
|
||||
|
||||
// test double connection (we win)
|
||||
TORRENT_TEST(double_connection_win)
|
||||
{
|
||||
|
|
|
@ -88,7 +88,7 @@ void test_remove_torrent(remove_flags_t const remove_options
|
|||
file.close();
|
||||
|
||||
wait_for_listen(ses1, "ses1");
|
||||
wait_for_listen(ses2, "ses1");
|
||||
wait_for_listen(ses2, "ses2");
|
||||
|
||||
// test using piece sizes smaller than 16kB
|
||||
std::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
|
||||
|
@ -101,6 +101,11 @@ void test_remove_torrent(remove_flags_t const remove_options
|
|||
std::fill(priorities.begin(), priorities.begin() + (num_pieces / 2), dont_download);
|
||||
tor2.prioritize_pieces(priorities);
|
||||
}
|
||||
else if (test == mid_download)
|
||||
{
|
||||
tor1.set_upload_limit(static_cast<int>(t->total_size()));
|
||||
tor2.set_download_limit(static_cast<int>(t->total_size()));
|
||||
}
|
||||
|
||||
torrent_status st1;
|
||||
torrent_status st2;
|
||||
|
|
|
@ -327,8 +327,11 @@ namespace {
|
|||
bool connect_alert(lt::alert const* a, tcp::endpoint& ep)
|
||||
{
|
||||
if (peer_connect_alert const* pc = alert_cast<peer_connect_alert>(a))
|
||||
{
|
||||
ep = pc->endpoint;
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void test_udp_tracker(std::string const& iface, address tracker, tcp::endpoint const& expected_peer)
|
||||
|
|
|
@ -154,7 +154,7 @@ namespace // TODO: remove this nested namespace
|
|||
};
|
||||
}
|
||||
|
||||
void run_upnp_test(char const* root_filename, char const* router_model, char const* control_name, int igd_version)
|
||||
void run_upnp_test(char const* root_filename, char const* control_name, int igd_version)
|
||||
{
|
||||
lt::io_service ios;
|
||||
|
||||
|
@ -208,12 +208,12 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con
|
|||
ec.clear();
|
||||
break;
|
||||
}
|
||||
if (upnp_handler->router_model() != "") break;
|
||||
if (!upnp_handler->router_model().empty()) break;
|
||||
std::this_thread::sleep_for(lt::milliseconds(100));
|
||||
}
|
||||
|
||||
std::cout << "router: " << upnp_handler->router_model() << std::endl;
|
||||
TEST_EQUAL(upnp_handler->router_model(), router_model);
|
||||
TEST_CHECK(!upnp_handler->router_model().empty());
|
||||
|
||||
auto const mapping1 = upnp_handler->add_mapping(portmap_protocol::tcp, 500, ep("127.0.0.1", 500));
|
||||
auto const mapping2 = upnp_handler->add_mapping(portmap_protocol::udp, 501, ep("127.0.0.1", 501));
|
||||
|
@ -272,9 +272,9 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con
|
|||
|
||||
TORRENT_TEST(upnp)
|
||||
{
|
||||
run_upnp_test(combine_path("..", "root1.xml").c_str(), "Xtreme N GIGABIT Router", "wipconn", 1);
|
||||
run_upnp_test(combine_path("..", "root2.xml").c_str(), "D-Link Router", "WANIPConnection", 1);
|
||||
run_upnp_test(combine_path("..", "root3.xml").c_str(), "D-Link Router", "WANIPConnection_2", 2);
|
||||
run_upnp_test(combine_path("..", "root1.xml").c_str(), "wipconn", 1);
|
||||
run_upnp_test(combine_path("..", "root2.xml").c_str(), "WANIPConnection", 1);
|
||||
run_upnp_test(combine_path("..", "root3.xml").c_str(), "WANIPConnection_2", 2);
|
||||
}
|
||||
|
||||
TORRENT_TEST(upnp_max_mappings)
|
||||
|
|
|
@ -216,22 +216,20 @@ void test_transfer(lt::session& ses, std::shared_ptr<torrent_info> torrent_file
|
|||
|
||||
if (st.is_seeding)
|
||||
{
|
||||
boost::int64_t const total_blocks = (torrent_file->total_size() + 0x3fff) / 0x4000;
|
||||
// we need to sleep here a bit to let the session sync with the torrent stats
|
||||
// commented out because it takes such a long time
|
||||
for (int i = 0; i < 50; ++i)
|
||||
{
|
||||
cnt = get_counters(ses);
|
||||
if (cnt["disk.read_cache_blocks"]
|
||||
== (torrent_file->total_size() + 0x3fff) / 0x4000
|
||||
&& cnt["disk.disk_blocks_in_use"]
|
||||
== (torrent_file->total_size() + 0x3fff) / 0x4000)
|
||||
if (std::abs(int(cnt["disk.read_cache_blocks"] - total_blocks)) <= 2 &&
|
||||
std::abs(int(cnt["disk.disk_blocks_in_use"] - total_blocks)) <= 2)
|
||||
break;
|
||||
std::printf("cache_size: %d/%d\n", int(cnt["disk.read_cache_blocks"])
|
||||
, int(cnt["disk.disk_blocks_in_use"]));
|
||||
std::this_thread::sleep_for(lt::milliseconds(100));
|
||||
}
|
||||
TEST_CHECK(std::abs(int(cnt["disk.disk_blocks_in_use"]
|
||||
- (torrent_file->total_size() + 0x3fff) / 0x4000)) <= 2);
|
||||
TEST_CHECK(std::abs(int(cnt["disk.disk_blocks_in_use"] - total_blocks)) <= 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue