Skip to content

Commit

Permalink
merged RC_2_0 into master
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed Nov 16, 2024
2 parents d265cac + 4b4003d commit f451871
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 11 deletions.
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

2.0.11 not released

* fix race condition when cancelling requests after becoming a seed
* fix performance bug in the file pool, evicting MRU instead of LRU (HanabishiRecca)
* fix bug where file_progress could sometimes be reported as >100%
* don't hint FADV_RANDOM on posix systems. May improve seeding performance
Expand All @@ -30,6 +31,7 @@
* fix integer overflow in piece picker
* torrent_status::num_pieces counts pieces passed hash check, as documented
* check settings_pack::max_out_request_queue before performance alert
* add announce_port setting to override the port announced to trackers

2.0.10 released

Expand Down
1 change: 1 addition & 0 deletions bindings/c/include/libtorrent_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ enum settings_tags_t {
SET_I2P_OUTBOUND_QUANTITY, // int
SET_I2P_INBOUND_LENGTH, // int
SET_I2P_OUTBOUND_LENGTH, // int
SET_ANNOUNCE_PORT, // int
SET_MIN_WEBSOCKET_ANNOUNCE_INTERVAL, // int
SET_WEBTORRENT_CONNECTION_TIMEOUT, // int
};
Expand Down
1 change: 1 addition & 0 deletions bindings/c/src/settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ int settings_key(int const tag)
case SET_I2P_OUTBOUND_QUANTITY: return sp::i2p_outbound_quantity;
case SET_I2P_INBOUND_LENGTH: return sp::i2p_inbound_length;
case SET_I2P_OUTBOUND_LENGTH: return sp::i2p_outbound_length;
case SET_ANNOUNCE_PORT: return sp::announce_port;
case SET_MIN_WEBSOCKET_ANNOUNCE_INTERVAL: return sp::min_websocket_announce_interval;
case SET_WEBTORRENT_CONNECTION_TIMEOUT: return sp::webtorrent_connection_timeout;
default:
Expand Down
1 change: 1 addition & 0 deletions include/libtorrent/session_handle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ namespace aux { struct torrent; }
// specified info-hash, advertising the specified port. If the port is
// left at its default, 0, the port will be implied by the DHT message's
// source port (which may improve connectivity through a NAT).
// ``dht_announce()`` is not affected by the ``announce_port`` override setting.
//
// Both these functions are exposed for advanced custom use of the DHT.
// All torrents eligible to be announce to the DHT will be automatically,
Expand Down
14 changes: 14 additions & 0 deletions include/libtorrent/settings_pack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2050,6 +2050,20 @@ namespace aux {
i2p_inbound_length,
i2p_outbound_length,

// ``announce_port`` is the port passed along as the ``port`` parameter
// to remote trackers such as HTTP or DHT. This setting does not affect
// the effective listening port nor local service discovery announcements.
// If left as zero (default), the listening port value is used.
//
// .. note::
// This setting is only meant for very special cases where a
// seed's listening port differs from the external port. As an
// example, if a local proxy is used and that the proxy supports
// reverse tunnels through NAT-PMP, the tracker must connect to
// the external NAT-PMP port (configured using ``announce_port``)
// instead of the actual local listening port.
announce_port,

// this is the minimum allowed announce interval for a WebSocket
// tracker used by WebTorrent to signal WebRTC connections. This is
// specified in seconds and is used as a sanity check on what is
Expand Down
84 changes: 84 additions & 0 deletions simulation/test_tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,90 @@ void on_alert_notify(lt::session* ses)
});
}

void test_announce()
{
using sim::asio::ip::address_v4;
sim::default_config network_cfg;
sim::simulation sim{network_cfg};

sim::asio::io_context web_server(sim, make_address_v4("2.2.2.2"));

// listen on port 8080
sim::http_server http(web_server, 8080);

int announces = 0;

// expect announced IP & port
std::string const expect_port = "&port=1234";
std::string const expect_ip = "&ip=1.2.3.4";

http.register_handler("/announce"
, [&announces, expect_port, expect_ip](std::string method, std::string req
, std::map<std::string, std::string>&)
{
++announces;
TEST_EQUAL(method, "GET");
TEST_CHECK(req.find(expect_port) != std::string::npos);
TEST_CHECK(req.find(expect_ip) != std::string::npos);
char response[500];
int const size = std::snprintf(response, sizeof(response), "d8:intervali1800e5:peers0:e");
return sim::send_response(200, "OK", size) + response;
});

{
lt::session_proxy zombie;

std::vector<asio::ip::address> ips;
ips.push_back(make_address("123.0.0.3"));

asio::io_context ios(sim, ips);
lt::settings_pack sett = settings();
sett.set_str(settings_pack::listen_interfaces, "0.0.0.0:6881");
sett.set_str(settings_pack::announce_ip, "1.2.3.4");
sett.set_int(settings_pack::announce_port, 1234);

auto ses = std::make_unique<lt::session>(sett, ios);

ses->set_alert_notify(std::bind(&on_alert_notify, ses.get()));

lt::add_torrent_params p;
p.name = "test-torrent";
p.save_path = ".";
p.info_hashes.v1.assign("abababababababababab");

p.trackers.push_back("http://2.2.2.2:8080/announce");
ses->async_add_torrent(p);

// stop the torrent 5 seconds in
sim::timer t1(sim, lt::seconds(5)
, [&ses](boost::system::error_code const&)
{
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
for (auto const& t : torrents)
{
t.pause();
}
});

// then shut down 10 seconds in
sim::timer t2(sim, lt::seconds(10)
, [&ses,&zombie](boost::system::error_code const&)
{
zombie = ses->abort();
ses.reset();
});

sim.run();
}

TEST_EQUAL(announces, 2);
}

// this test makes sure that a seed can overwrite its announced IP & port
TORRENT_TEST(announce_ip_port) {
test_announce();
}

static const int num_interfaces = 3;

void test_ipv6_support(char const* listen_interfaces
Expand Down
2 changes: 1 addition & 1 deletion src/peer_connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4010,7 +4010,7 @@ namespace {
INVARIANT_CHECK;

auto t = m_torrent.lock();
TORRENT_ASSERT(t);
if (!t) return;

if (m_disconnecting) return;

Expand Down
2 changes: 0 additions & 2 deletions src/piece_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3786,8 +3786,6 @@ namespace {
TORRENT_ASSERT(info.peer == nullptr || info.peer->in_use);
TORRENT_ASSERT(info.piece_index == block.piece_index);

TORRENT_ASSERT(info.state != block_info::state_none);

if (info.state != block_info::state_requested) return;

piece_pos const& p = m_piece_map[block.piece_index];
Expand Down
8 changes: 5 additions & 3 deletions src/session_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1261,9 +1261,11 @@ namespace {
#endif
req.ssl_ctx = &m_ssl_ctx;
#endif

auto ls = req.outgoing_socket.get();
if (ls)
if (const auto announce_port = std::uint16_t(m_settings.get_int(settings_pack::announce_port)))
{
req.listen_port = announce_port;
}
else if (auto ls = req.outgoing_socket.get())
{
req.listen_port =
#ifdef TORRENT_SSL_PEERS
Expand Down
3 changes: 2 additions & 1 deletion src/settings_pack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,8 @@ namespace {
SET(i2p_inbound_length, 3, nullptr),
SET(i2p_outbound_length, 3, nullptr),
SET(min_websocket_announce_interval, 1 * 60, nullptr),
SET(webtorrent_connection_timeout, 2 * 60, nullptr)
SET(webtorrent_connection_timeout, 2 * 60, nullptr),
SET(announce_port, 0, nullptr)
}});

#undef SET
Expand Down
16 changes: 12 additions & 4 deletions src/torrent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2815,23 +2815,25 @@ bool is_downloading_state(int const st)
// If this is an SSL torrent the announce needs to specify an SSL
// listen port. DHT nodes only operate on non-SSL ports so SSL
// torrents cannot use implied_port.
// if we allow incoming uTP connections, set the implied_port
// argument in the announce, this will make the DHT node use
// if we allow incoming uTP connections and don't overwrite
// the announced port, set the implied_port argument
// in the announce, this will make the DHT node use
// our source port in the packet as our listen port, which is
// likely more accurate when behind a NAT
const auto announce_port = std::uint16_t(settings().get_int(settings_pack::announce_port));
if (is_ssl_torrent())
{
flags |= dht::announce::ssl_torrent;
}
else if (settings().get_bool(settings_pack::enable_incoming_utp))
else if (!announce_port && settings().get_bool(settings_pack::enable_incoming_utp))
{
flags |= dht::announce::implied_port;
}

std::weak_ptr<torrent> self(shared_from_this());
m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version v)
{
m_ses.dht()->announce(ih, 0, flags
m_ses.dht()->announce(ih, announce_port, flags
, std::bind(&torrent::on_dht_announce_response_disp, self, v, _1));
});
}
Expand Down Expand Up @@ -5178,6 +5180,10 @@ namespace {
#ifndef TORRENT_DISABLE_STREAMING
void torrent::cancel_non_critical()
{
// if we don't have a piece picker, there's nothing to cancel.
// e.g. We may have become a seed already.
if (!has_picker()) return;

std::set<piece_index_t> time_critical;
for (auto const& p : m_time_critical_pieces)
time_critical.insert(p.piece);
Expand Down Expand Up @@ -6015,6 +6021,8 @@ namespace {
{
INVARIANT_CHECK;

TORRENT_ASSERT(has_picker());

for (auto* p : m_connections)
{
TORRENT_INCREMENT(m_iterating_connections);
Expand Down
32 changes: 32 additions & 0 deletions test/test_piece_picker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,38 @@ TORRENT_TEST(piece_block)
TEST_CHECK(!(piece_block(zero, 1) < piece_block(zero, 1)));
}

TORRENT_TEST(abort_download_states)
{
auto p = setup_picker("1111111", " ", "7110000", "");

//aborting a block that isn't being downloaded is a no-op
TEST_CHECK(p->is_requested({3_piece, 0}) == false);
p->abort_download({3_piece, 0}, tmp_peer);
p->abort_download({3_piece, 1}, tmp_peer);
TEST_CHECK(p->is_requested({3_piece, 0}) == false);

// aborting a block that's downloading
p->mark_as_downloading({3_piece, 0}, tmp_peer);
TEST_CHECK(p->is_downloaded({3_piece, 0}) == false);
p->abort_download({3_piece, 0}, tmp_peer);
p->abort_download({3_piece, 1}, tmp_peer);
TEST_CHECK(p->is_downloaded({3_piece, 0}) == false);

// aborting a block that's finished is a no-op
p->mark_as_writing({3_piece, 0}, tmp_peer);
TEST_CHECK(p->is_downloaded({3_piece, 0}) == true);
p->abort_download({3_piece, 0}, tmp_peer);
p->abort_download({3_piece, 1}, tmp_peer);
TEST_CHECK(p->is_downloaded({3_piece, 0}) == true);

// aborting a block that's written is a no-op
p->mark_as_finished({3_piece, 0}, tmp_peer);
TEST_CHECK(p->is_finished({3_piece, 0}) == true);
p->abort_download({3_piece, 0}, tmp_peer);
p->abort_download({3_piece, 1}, tmp_peer);
TEST_CHECK(p->is_finished({3_piece, 0}) == true);
}

TORRENT_TEST(abort_download)
{
// test abort_download
Expand Down

0 comments on commit f451871

Please sign in to comment.