merged RC_1_1 into master

This commit is contained in:
arvidn 2019-01-11 12:22:47 +01:00
commit 8b067310b1
10 changed files with 138 additions and 78 deletions

View File

@ -740,7 +740,11 @@ if(developer-options)
ENABLED TORRENT_PROFILE_CALLS=1)
endif()
generate_and_install_pkg_config_file(torrent-rasterbar libtorrent-rasterbar)
# There is little to none support for using pkg-config with MSVC and most users won't bother with it.
# However, msys is a linux-like platform on Windows that do support/prefer using pkg-config.
if (NOT MSVC)
generate_and_install_pkg_config_file(torrent-rasterbar libtorrent-rasterbar)
endif()
include(CheckCXXCompilerFlag)

View File

@ -47,6 +47,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <sys/stat.h>
#endif
#ifdef TORRENT_UTP_LOG_ENABLE
#include "libtorrent/utp_stream.hpp"
#endif
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/announce_entry.hpp"
#include "libtorrent/entry.hpp"
@ -1022,8 +1026,13 @@ CLIENT OPTIONS
previous command line options, so be sure to specify this first
-G Add torrents in seed-mode (i.e. assume all pieces
are present and check hashes on-demand)
-O print session stats counters to the log
-O print session stats counters to the log)"
#ifdef TORRENT_UTP_LOG_ENABLE
R"(
-q Enable uTP transport-level verbose logging
)"
#endif
R"(
LIBTORRENT SETTINGS
--<name-of-setting>=<value>
set the libtorrent setting <name> to <value>
@ -1190,6 +1199,11 @@ example alert_masks:
case 'G': seed_mode = true; --i; break;
case 's': save_path = make_absolute_path(arg); break;
case 'O': stats_enabled = true; --i; break;
#ifdef TORRENT_UTP_LOG_ENABLE
case 'q':
libtorrent::set_utp_stream_logging(true);
break;
#endif
case 'U': torrent_upload_limit = atoi(arg) * 1000; break;
case 'D': torrent_download_limit = atoi(arg) * 1000; break;
case 'm': monitor_dir = make_absolute_path(arg); break;

View File

@ -78,8 +78,9 @@ namespace libtorrent {
packet_ptr insert(index_type idx, packet_ptr value);
int size() const
{ return m_size; }
int size() const { return m_size; }
bool empty() const { return m_size == 0; }
std::uint32_t capacity() const
{ return m_capacity; }

View File

@ -1659,6 +1659,11 @@ namespace libtorrent {
// systems.
close_file_interval,
// When uTP experiences packet loss, it will reduce the congestion
// window, and not reduce it again for this many milliseconds, even if
// experiencing another lost packet.
utp_cwnd_reduce_timer,
// the max number of web seeds to have connected per torrent at any
// given time.
max_web_seed_connections,

View File

@ -107,6 +107,7 @@ namespace libtorrent {
int connect_timeout() const { return m_sett.get_int(settings_pack::utp_connect_timeout); }
int min_timeout() const { return m_sett.get_int(settings_pack::utp_min_timeout); }
int loss_multiplier() const { return m_sett.get_int(settings_pack::utp_loss_multiplier); }
int cwnd_reduce_timer() const { return m_sett.get_int(settings_pack::utp_cwnd_reduce_timer); }
std::pair<int, int> mtu_for_dest(address const& addr);
int num_sockets() const { return int(m_utp_sockets.size()); }

View File

@ -285,7 +285,7 @@ struct sim_config : sim::default_config
{
if (hostname == "tracker.com")
{
result.push_back(address_v4::from_string("10.0.0.2"));
result.push_back(address_v4::from_string("123.0.0.2"));
if (ipv6)
result.push_back(address_v6::from_string("ff::dead:beef"));
return duration_cast<chrono::high_resolution_clock::duration>(chrono::milliseconds(100));
@ -323,7 +323,7 @@ void test_ipv6_support(char const* listen_interfaces
sim_config network_cfg;
sim::simulation sim{network_cfg};
sim::asio::io_service web_server_v4(sim, address_v4::from_string("10.0.0.2"));
sim::asio::io_service web_server_v4(sim, address_v4::from_string("123.0.0.2"));
sim::asio::io_service web_server_v6(sim, address_v6::from_string("ff::dead:beef"));
// listen on port 8080
@ -370,7 +370,7 @@ void test_ipv6_support(char const* listen_interfaces
for (int i = 0; i < num_interfaces; i++)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "10.0.0.%d", i + 1);
std::snprintf(ep, sizeof(ep), "123.0.0.%d", i + 1);
ips.push_back(address::from_string(ep));
std::snprintf(ep, sizeof(ep), "ffff::1337:%d", i + 1);
ips.push_back(address::from_string(ep));
@ -428,7 +428,7 @@ void test_udpv6_support(char const* listen_interfaces
sim_config network_cfg;
sim::simulation sim{network_cfg};
sim::asio::io_service web_server_v4(sim, address_v4::from_string("10.0.0.2"));
sim::asio::io_service web_server_v4(sim, address_v4::from_string("123.0.0.2"));
sim::asio::io_service web_server_v6(sim, address_v6::from_string("ff::dead:beef"));
int v4_announces = 0;
@ -442,7 +442,7 @@ void test_udpv6_support(char const* listen_interfaces
for (int i = 0; i < num_interfaces; i++)
{
char ep[30];
std::snprintf(ep, sizeof(ep), "10.0.0.%d", i + 1);
std::snprintf(ep, sizeof(ep), "123.0.0.%d", i + 1);
ips.push_back(address::from_string(ep));
std::snprintf(ep, sizeof(ep), "ffff::1337:%d", i + 1);
ips.push_back(address::from_string(ep));
@ -555,7 +555,7 @@ TORRENT_TEST(ipv6_support_bind_v6_any)
TORRENT_TEST(ipv6_support_bind_v4)
{
test_ipv6_support("10.0.0.3:6881", 2, 0);
test_ipv6_support("123.0.0.3:6881", 2, 0);
}
TORRENT_TEST(ipv6_support_bind_v6)
@ -570,12 +570,12 @@ TORRENT_TEST(ipv6_support_bind_v6_3interfaces)
TORRENT_TEST(ipv6_support_bind_v4_v6)
{
test_ipv6_support("10.0.0.3:6881,[ffff::1337:1]:6881", 2, 2);
test_ipv6_support("123.0.0.3:6881,[ffff::1337:1]:6881", 2, 2);
}
TORRENT_TEST(ipv6_support_bind_v6_v4)
{
test_ipv6_support("[ffff::1337:1]:6881,10.0.0.3:6881", 2, 2);
test_ipv6_support("[ffff::1337:1]:6881,123.0.0.3:6881", 2, 2);
}
// this runs a simulation of a torrent with tracker(s), making sure the request
@ -584,7 +584,7 @@ TORRENT_TEST(ipv6_support_bind_v6_v4)
// trackers to the torrent. It's expected to return the number of seconds to
// wait until test2 is called.
// The Announce function is called on http requests. Test1 is run on the session
// 5 seconds after startup. The tracker is running at 10.0.0.2 (or tracker.com)
// 5 seconds after startup. The tracker is running at 123.0.0.2 (or tracker.com)
// port 8080.
template <typename Setup, typename Announce, typename Test1, typename Test2>
void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
@ -594,7 +594,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
sim_config network_cfg;
sim::simulation sim{network_cfg};
sim::asio::io_service tracker_ios(sim, address_v4::from_string("10.0.0.2"));
sim::asio::io_service tracker_ios(sim, address_v4::from_string("123.0.0.2"));
sim::asio::io_service tracker_ios6(sim, address_v6::from_string("ff::dead:beef"));
// listen on port 8080
@ -606,7 +606,7 @@ void tracker_test(Setup setup, Announce a, Test1 test1, Test2 test2
lt::session_proxy zombie;
asio::io_service ios(sim, { address_v4::from_string("10.0.0.3")
asio::io_service ios(sim, { address_v4::from_string("123.0.0.3")
, address_v6::from_string("ffff::1337") });
lt::settings_pack sett = settings();
std::unique_ptr<lt::session> ses(new lt::session(sett, ios));
@ -976,7 +976,7 @@ TORRENT_TEST(tracker_ipv6_argument)
{
settings_pack pack;
pack.set_bool(settings_pack::anonymous_mode, false);
pack.set_str(settings_pack::listen_interfaces, "10.0.0.3:0,[ffff::1337]:0");
pack.set_str(settings_pack::listen_interfaces, "123.0.0.3:0,[ffff::1337]:0");
ses.apply_settings(pack);
p.ti = make_torrent(true);
return 60;
@ -1000,7 +1000,7 @@ TORRENT_TEST(tracker_ipv6_argument)
std::string::size_type const pos = req.find("&ipv4=");
TEST_CHECK(pos != std::string::npos || stop_event);
got_ipv4 |= pos != std::string::npos;
TEST_EQUAL(req.substr(pos + 6, req.substr(pos + 6).find_first_of('&')), "10.0.0.3");
TEST_EQUAL(req.substr(pos + 6, req.substr(pos + 6).find_first_of('&')), "123.0.0.3");
}
return sim::send_response(200, "OK", 11) + "d5:peers0:e";
}

View File

@ -341,6 +341,7 @@ constexpr int CLOSE_FILE_INTERVAL = 0;
SET(urlseed_max_request_bytes, 16 * 1024 * 1024, nullptr),
SET(web_seed_name_lookup_retry, 1800, nullptr),
SET(close_file_interval, CLOSE_FILE_INTERVAL, nullptr),
SET(utp_cwnd_reduce_timer, 100, nullptr),
SET(max_web_seed_connections, 3, nullptr),
SET(resolver_cache_timeout, 1200, &session_impl::update_resolver_cache_timeout),
}});

View File

@ -2832,9 +2832,15 @@ bool is_downloading_state(int const st)
tcp::endpoint const ep = s.get_local_endpoint();
if (is_any(ep.address())) return;
if (is_v6(ep))
req.ipv6.push_back(ep.address().to_v6());
{
if (!is_local(ep.address()) && !is_loopback(ep.address()))
req.ipv6.push_back(ep.address().to_v6());
}
else
req.ipv4.push_back(ep.address().to_v4());
{
if (!is_local(ep.address()) && !is_loopback(ep.address()))
req.ipv4.push_back(ep.address().to_v4());
}
});
}

View File

@ -289,7 +289,7 @@ struct utp_socket_impl
bool consume_incoming_data(
utp_header const* ph, std::uint8_t const* ptr, int payload_size, time_point now);
void update_mtu_limits();
void experienced_loss(std::uint32_t seq_nr);
void experienced_loss(std::uint32_t seq_nr, time_point now);
void set_state(int s);
@ -394,6 +394,10 @@ struct utp_socket_impl
// the last time we stepped the timestamp history
time_point m_last_history_step = clock_type::now();
// the next time we allow a lost packet to halve cwnd. We only do this once every
// 100 ms
time_point m_next_loss;
// the max number of bytes in-flight. This is a fixed point
// value, to get the true number of bytes, shift right 16 bits
// the value is always >= 0, but the calculations performed on
@ -1533,6 +1537,8 @@ std::pair<std::uint32_t, int> utp_socket_impl::parse_sack(std::uint16_t const pa
if (ack_nr == m_seq_nr) break;
}
if (m_outbuf.empty()) m_duplicate_acks = 0;
// now, scan the bits in reverse, and count the number of ACKed packets. Only
// lost packets followed by 'dup_ack_limit' packets may be resent
// start with the sequence number represented by the last bit in the SACK
@ -1587,19 +1593,20 @@ std::pair<std::uint32_t, int> utp_socket_impl::parse_sack(std::uint16_t const pa
packet* p = m_outbuf.at(pkt_seq);
UTP_LOGV("%8p: Packet %d lost. (fast_resend_seq_nr:%d trigger fast-resend)\n"
, static_cast<void*>(this), pkt_seq, m_fast_resend_seq_nr);
if (p)
if (!p) continue;
// don't cut cwnd if the packet we lost was the MTU probe
// the logic to handle a lost MTU probe is in resend_packet()
if (cut_cwnd && (pkt_seq != m_mtu_seq || m_mtu_seq == 0))
{
if (resend_packet(p, true))
{
m_duplicate_acks = 0;
m_fast_resend_seq_nr = (pkt_seq + 1) & ACK_MASK;
}
experienced_loss(pkt_seq, now);
cut_cwnd = false;
}
if (cut_cwnd)
if (resend_packet(p, true))
{
experienced_loss(pkt_seq);
cut_cwnd = false;
m_duplicate_acks = 0;
m_fast_resend_seq_nr = (pkt_seq + 1) & ACK_MASK;
}
}
@ -2251,7 +2258,7 @@ bool utp_socket_impl::resend_packet(packet* p, bool fast_resend)
return !m_stalled;
}
void utp_socket_impl::experienced_loss(std::uint32_t const seq_nr)
void utp_socket_impl::experienced_loss(std::uint32_t const seq_nr, time_point const now)
{
INVARIANT_CHECK;
@ -2271,11 +2278,17 @@ void utp_socket_impl::experienced_loss(std::uint32_t const seq_nr)
// same packet again, ignore it.
if (compare_less_wrap(seq_nr, m_loss_seq_nr + 1, ACK_MASK)) return;
// don't reduce cwnd more than once every 100ms
if (m_next_loss >= now) return;
m_next_loss = now + milliseconds(m_sm.cwnd_reduce_timer());
// cut window size in 2
m_cwnd = std::max(m_cwnd * m_sm.loss_multiplier() / 100
, std::int64_t(m_mtu) * (1 << 16));
m_loss_seq_nr = m_seq_nr;
UTP_LOGV("%8p: Lost packet %d caused cwnd cut\n", static_cast<void*>(this), seq_nr);
UTP_LOGV("%8p: Lost packet %d caused cwnd cut. m_loss_seq_nr:%d\n"
, static_cast<void*>(this), seq_nr, m_seq_nr);
// if we happen to be in slow-start mode, we need to leave it
// note that we set ssthres to the window size _after_ reducing it. Next slow
@ -2875,6 +2888,8 @@ bool utp_socket_impl::incoming_packet(span<std::uint8_t const> buf
++m_duplicate_acks;
}
TORRENT_ASSERT_VAL(m_outbuf.size() > 0 || m_duplicate_acks == 0, m_duplicate_acks);
std::uint32_t min_rtt = std::numeric_limits<std::uint32_t>::max();
TORRENT_ASSERT(m_outbuf.at((m_acked_seq_nr + 1) & ACK_MASK) || ((m_seq_nr - m_acked_seq_nr) & ACK_MASK) <= 1);
@ -2904,6 +2919,7 @@ bool utp_socket_impl::incoming_packet(span<std::uint8_t const> buf
}
maybe_inc_acked_seq_nr();
if (m_outbuf.empty()) m_duplicate_acks = 0;
}
// look for extended headers
@ -2969,7 +2985,9 @@ bool utp_socket_impl::incoming_packet(span<std::uint8_t const> buf
if (p)
{
experienced_loss(m_fast_resend_seq_nr);
// don't consider a lost probe as proper loss, it doesn't necessarily
// signal congestion
if (!p->mtu_probe) experienced_loss(m_fast_resend_seq_nr, receive_time);
resend_packet(p, true);
if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return true;
}
@ -3178,6 +3196,8 @@ bool utp_socket_impl::incoming_packet(span<std::uint8_t const> buf
if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return true;
}
TORRENT_ASSERT(!compare_less_wrap(m_seq_nr, m_acked_seq_nr, ACK_MASK));
#if TORRENT_UTP_LOG
if (sample && acked_bytes && prev_bytes_in_flight)
{
@ -3246,7 +3266,7 @@ bool utp_socket_impl::incoming_packet(span<std::uint8_t const> buf
, packet_timeout()
, int(total_milliseconds(m_timeout - receive_time))
, int(total_microseconds(receive_time.time_since_epoch()))
, (m_seq_nr - m_acked_seq_nr) & ACK_MASK
, m_outbuf.size()
, m_mtu
, their_delay_base
, std::uint32_t(m_reply_micro)
@ -3532,7 +3552,20 @@ void utp_socket_impl::tick(time_point const now)
if (now > m_timeout)
{
// TIMEOUT!
// set cwnd to 1 MSS
bool ignore_loss = false;
if (((m_acked_seq_nr + 1) & ACK_MASK) == m_mtu_seq
&& ((m_seq_nr - 1) & ACK_MASK) == m_mtu_seq
&& m_mtu_seq != 0)
{
// we timed out, and the only outstanding packet
// we had was the probe. Assume it was dropped
// because it was too big
m_mtu_ceiling = m_mtu - 1;
update_mtu_limits();
ignore_loss = true;
}
// the close_reason here is a bit of a hack. When it's set, it indicates
// that the upper layer intends to close the socket. However, it has been
@ -3541,7 +3574,9 @@ void utp_socket_impl::tick(time_point const now)
// other end. This catches that case and let the socket time out.
if (m_outbuf.size() || m_close_reason != close_reason_t::none)
{
++m_num_timeouts;
// m_num_timeouts is used to update the connection timeout, and if we
// lose this packet because it's an MTU-probe, don't change the timeout
if (!ignore_loss) ++m_num_timeouts;
m_sm.inc_stats_counter(counters::utp_timeout);
}
@ -3567,52 +3602,45 @@ void utp_socket_impl::tick(time_point const now)
return;
}
if (((m_acked_seq_nr + 1) & ACK_MASK) == m_mtu_seq
&& ((m_seq_nr - 1) & ACK_MASK) == m_mtu_seq
&& m_mtu_seq != 0)
if (!ignore_loss)
{
// we timed out, and the only outstanding packet
// we had was the probe. Assume it was dropped
// because it was too big
m_mtu_ceiling = m_mtu - 1;
update_mtu_limits();
// set cwnd to 1 MSS
if (m_bytes_in_flight == 0 && (m_cwnd >> 16) >= m_mtu)
{
// this is just a timeout because this direction of
// the stream is idle. Don't reset the cwnd, just decay it
m_cwnd = std::max(m_cwnd * 2 / 3, std::int64_t(m_mtu) * (1 << 16));
}
else
{
// we timed out because a packet was not ACKed or because
// the cwnd was made smaller than one packet
m_cwnd = std::int64_t(m_mtu) * (1 << 16);
}
TORRENT_ASSERT(m_cwnd >= 0);
m_timeout = now + milliseconds(packet_timeout());
UTP_LOGV("%8p: resetting cwnd:%d\n"
, static_cast<void*>(this), int(m_cwnd >> 16));
// since we've already timed out now, don't count
// loss that we might detect for packets that just
// timed out
m_loss_seq_nr = m_seq_nr;
// when we time out, the cwnd is reset to 1 MSS, which means we
// need to ramp it up quickly again. enter slow start mode. This time
// we're very likely to have an ssthres set, which will make us leave
// slow start before inducing more delay or loss.
m_slow_start = true;
UTP_LOGV("%8p: slow_start -> 1\n", static_cast<void*>(this));
}
if (m_bytes_in_flight == 0 && (m_cwnd >> 16) >= m_mtu)
{
// this is just a timeout because this direction of
// the stream is idle. Don't reset the cwnd, just decay it
m_cwnd = std::max(m_cwnd * 2 / 3, std::int64_t(m_mtu) * (1 << 16));
}
else
{
// we timed out because a packet was not ACKed or because
// the cwnd was made smaller than one packet
m_cwnd = std::int64_t(m_mtu) * (1 << 16);
}
TORRENT_ASSERT(m_cwnd >= 0);
m_timeout = now + milliseconds(packet_timeout());
UTP_LOGV("%8p: resetting cwnd:%d\n"
, static_cast<void*>(this), int(m_cwnd >> 16));
// we dropped all packets, that includes the mtu probe
m_mtu_seq = 0;
// since we've already timed out now, don't count
// loss that we might detect for packets that just
// timed out
m_loss_seq_nr = m_seq_nr;
// when we time out, the cwnd is reset to 1 MSS, which means we
// need to ramp it up quickly again. enter slow start mode. This time
// we're very likely to have an ssthres set, which will make us leave
// slow start before inducing more delay or loss.
m_slow_start = true;
UTP_LOGV("%8p: slow_start -> 1\n", static_cast<void*>(this));
// we need to go one past m_seq_nr to cover the case
// where we just sent a SYN packet and then adjusted for
// the uTorrent sequence number reuse

View File

@ -257,6 +257,6 @@ TORRENT_TEST(settings_pack_abi)
TEST_EQUAL(settings_pack::max_http_recv_buffer_size, settings_pack::int_type_base + 115);
TEST_EQUAL(settings_pack::web_seed_name_lookup_retry, settings_pack::int_type_base + 128);
TEST_EQUAL(settings_pack::close_file_interval, settings_pack::int_type_base + 129);
TEST_EQUAL(settings_pack::max_web_seed_connections, settings_pack::int_type_base + 130);
TEST_EQUAL(settings_pack::resolver_cache_timeout, settings_pack::int_type_base + 131);
TEST_EQUAL(settings_pack::max_web_seed_connections, settings_pack::int_type_base + 131);
TEST_EQUAL(settings_pack::resolver_cache_timeout, settings_pack::int_type_base + 132);
}