forked from premiere/premiere-libtorrent
merged uTP fixes from RC_0_16
This commit is contained in:
parent
811def7ae8
commit
de6a715092
|
@ -27,6 +27,9 @@
|
|||
* fix uTP edge case where udp socket buffer fills up
|
||||
* fix nagle implementation in uTP
|
||||
|
||||
* fix resend logic in response to uTP SACK messages
|
||||
* only act on uTP RST packets with correct ack_nr
|
||||
* make uTP errors log in normal log mode (not require verbose)
|
||||
* deduplicate web seed entries from torrent files
|
||||
* improve error reporting from lazy_decode()
|
||||
|
||||
|
|
|
@ -356,6 +356,8 @@ namespace libtorrent
|
|||
return true;
|
||||
}
|
||||
|
||||
if (ph->get_type() == ST_RESET) return false;
|
||||
|
||||
// #error send reset
|
||||
|
||||
return false;
|
||||
|
|
|
@ -165,6 +165,10 @@ struct packet
|
|||
// sent with the DF bit set (Don't Fragment)
|
||||
bool mtu_probe:1;
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
int num_fast_resend;
|
||||
#endif
|
||||
|
||||
// the actual packet buffer
|
||||
boost::uint8_t buf[];
|
||||
};
|
||||
|
@ -1233,6 +1237,9 @@ void utp_socket_impl::send_syn()
|
|||
p->size = sizeof(utp_header);
|
||||
p->header_size = sizeof(utp_header);
|
||||
p->num_transmissions = 0;
|
||||
#ifdef TORRENT_DEBUG
|
||||
p->num_fast_resend = 0;
|
||||
#endif
|
||||
p->need_resend = false;
|
||||
utp_header* h = (utp_header*)p->buf;
|
||||
h->type_ver = (ST_SYN << 4) | 1;
|
||||
|
@ -1443,9 +1450,10 @@ void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, boost::uint8_t cons
|
|||
{
|
||||
experienced_loss(m_fast_resend_seq_nr);
|
||||
int num_resent = 0;
|
||||
for (; m_fast_resend_seq_nr != last_ack; m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK)
|
||||
while (m_fast_resend_seq_nr != last_ack)
|
||||
{
|
||||
packet* p = (packet*)m_outbuf.at(m_fast_resend_seq_nr);
|
||||
m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK;
|
||||
if (!p) continue;
|
||||
++num_resent;
|
||||
if (!resend_packet(p, true)) break;
|
||||
|
@ -1699,6 +1707,9 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
p->size = packet_size;
|
||||
p->header_size = packet_size - payload_size;
|
||||
p->num_transmissions = 0;
|
||||
#ifdef TORRENT_DEBUG
|
||||
p->num_fast_resend = 0;
|
||||
#endif
|
||||
p->need_resend = false;
|
||||
ptr = p->buf;
|
||||
h = (utp_header*)ptr;
|
||||
|
@ -1811,7 +1822,8 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
}
|
||||
|
||||
h->timestamp_difference_microseconds = m_reply_micro;
|
||||
h->wnd_size = m_in_buf_size - m_buffered_incoming_bytes - m_receive_buffer_size;
|
||||
h->wnd_size = (std::max)(m_in_buf_size - m_buffered_incoming_bytes
|
||||
- m_receive_buffer_size, 0);
|
||||
h->ack_nr = m_ack_nr;
|
||||
|
||||
// if this is a FIN packet, override the type
|
||||
|
@ -2002,6 +2014,9 @@ bool utp_socket_impl::resend_packet(packet* p, bool fast_resend)
|
|||
m_sm->inc_stats_counter(utp_socket_manager::packet_resend);
|
||||
if (fast_resend) m_sm->inc_stats_counter(utp_socket_manager::fast_retransmit);
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
if (fast_resend) ++p->num_fast_resend;
|
||||
#endif
|
||||
p->need_resend = false;
|
||||
utp_header* h = (utp_header*)p->buf;
|
||||
// update packet header
|
||||
|
@ -2264,9 +2279,23 @@ bool utp_socket_impl::consume_incoming_data(
|
|||
{
|
||||
// What?! We've already received a FIN and everything up
|
||||
// to it has been acked. Ignore this packet
|
||||
UTP_LOG("%8p: ERROR: ignoring packet on shut down socket\n", this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_read_buffer_size == 0
|
||||
&& m_receive_buffer_size >= m_in_buf_size - m_buffered_incoming_bytes)
|
||||
{
|
||||
// if we don't have a buffer from the upper layer, and the
|
||||
// number of queued up bytes, waiting for the upper layer,
|
||||
// exceeds the advertized receive window, start ignoring
|
||||
// more data packets
|
||||
UTP_LOG("%8p: ERROR: our advertized window is not honored. "
|
||||
"recv_buf: %s buffered_in: %d max_size: %d\n"
|
||||
, this, m_receive_buffer_size, m_buffered_incoming_bytes, m_in_buf_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ph->seq_nr == ((m_ack_nr + 1) & ACK_MASK))
|
||||
{
|
||||
TORRENT_ASSERT(m_inbuf.at(m_ack_nr) == 0);
|
||||
|
@ -2339,6 +2368,9 @@ bool utp_socket_impl::consume_incoming_data(
|
|||
p->size = payload_size;
|
||||
p->header_size = 0;
|
||||
p->num_transmissions = 0;
|
||||
#ifdef TORRENT_DEBUG
|
||||
p->num_fast_resend = 0;
|
||||
#endif
|
||||
p->need_resend = false;
|
||||
memcpy(p->buf, ptr, payload_size);
|
||||
m_inbuf.insert(ph->seq_nr, p);
|
||||
|
@ -2434,7 +2466,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
|
||||
if (ph->get_version() != 1)
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet version:%d (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: incoming packet version:%d (ignored)\n"
|
||||
, this, int(ph->get_version()));
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return false;
|
||||
|
@ -2443,7 +2475,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
// SYN packets have special (reverse) connection ids
|
||||
if (ph->get_type() != ST_SYN && ph->connection_id != m_recv_id)
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet id:%d expected:%d (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: incoming packet id:%d expected:%d (ignored)\n"
|
||||
, this, int(ph->connection_id), int(m_recv_id));
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return false;
|
||||
|
@ -2451,7 +2483,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
|
||||
if (ph->get_type() >= NUM_TYPES)
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet type:%d (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: incoming packet type:%d (ignored)\n"
|
||||
, this, int(ph->get_type()));
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return false;
|
||||
|
@ -2465,7 +2497,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
|
||||
if (m_state != UTP_STATE_NONE && ph->get_type() == ST_SYN)
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet type:ST_SYN (ignored)\n", this);
|
||||
UTP_LOG("%8p: ERROR: incoming packet type:ST_SYN (ignored)\n", this);
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return true;
|
||||
}
|
||||
|
@ -2502,17 +2534,6 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
, this, m_reply_micro, prev_base ? base_change : 0);
|
||||
}
|
||||
|
||||
// TODO: 2 sequence number, source IP and connection ID should be
|
||||
// verified before accepting a reset packet
|
||||
if (ph->get_type() == ST_RESET)
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet type:RESET\n", this);
|
||||
m_error = asio::error::connection_reset;
|
||||
m_state = UTP_STATE_ERROR_WAIT;
|
||||
test_socket_state();
|
||||
return true;
|
||||
}
|
||||
|
||||
// is this ACK valid? If the other end is ACKing
|
||||
// a packet that hasn't been sent yet
|
||||
// just ignore it. A 3rd party could easily inject a packet
|
||||
|
@ -2531,7 +2552,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
if (m_state != UTP_STATE_NONE
|
||||
&& compare_less_wrap(cmp_seq_nr, ph->ack_nr, ACK_MASK))
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet ack_nr:%d our seq_nr:%d (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: incoming packet ack_nr:%d our seq_nr:%d (ignored)\n"
|
||||
, this, int(ph->ack_nr), m_seq_nr);
|
||||
m_sm->inc_stats_counter(utp_socket_manager::redundant_pkts_in);
|
||||
return true;
|
||||
|
@ -2564,9 +2585,11 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
// with a higher sequence number than the FIN sequence number
|
||||
if (m_eof && compare_less_wrap(m_eof_seq_nr, ph->seq_nr, ACK_MASK))
|
||||
{
|
||||
UTP_LOGV("%8p: incoming packet seq_nr:%d eof_seq_nr:%d (ignored)\n"
|
||||
, this, int(ph->seq_nr), m_eof_seq_nr);
|
||||
|
||||
#if TORRENT_UTP_LOG
|
||||
UTP_LOG("%8p: ERROR: incoming packet type: %s seq_nr:%d eof_seq_nr:%d (ignored)\n"
|
||||
, this, packet_type_names[ph->get_type()], int(ph->seq_nr), m_eof_seq_nr);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ph->get_type() == ST_DATA)
|
||||
|
@ -2581,12 +2604,33 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
// or a seariously damaged connection that lost a lot of
|
||||
// packets. Neither is very likely, and it should be OK
|
||||
// to drop the timestamp information.
|
||||
UTP_LOGV("%8p: incoming packet seq_nr:%d our ack_nr:%d (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: incoming packet seq_nr:%d our ack_nr:%d (ignored)\n"
|
||||
, this, int(ph->seq_nr), m_ack_nr);
|
||||
m_sm->inc_stats_counter(utp_socket_manager::redundant_pkts_in);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ph->get_type() == ST_RESET)
|
||||
{
|
||||
if (compare_less_wrap(cmp_seq_nr, ph->ack_nr, ACK_MASK))
|
||||
{
|
||||
UTP_LOG("%8p: ERROR: invalid RESET packet, ack_nr:%d our seq_nr:%d (ignored)\n"
|
||||
, this, int(ph->ack_nr), m_seq_nr);
|
||||
return true;
|
||||
}
|
||||
if (compare_less_wrap(ph->ack_nr, m_acked_seq_nr , ACK_MASK))
|
||||
{
|
||||
UTP_LOG("%8p: ERROR: invalid RESET packet, ack_nr:%d our acked_seq_nr:%d (ignored)\n"
|
||||
, this, int(ph->ack_nr), m_acked_seq_nr);
|
||||
return true;
|
||||
}
|
||||
UTP_LOGV("%8p: incoming packet type:RESET\n", this);
|
||||
m_error = asio::error::connection_reset;
|
||||
m_state = UTP_STATE_ERROR_WAIT;
|
||||
test_socket_state();
|
||||
return true;
|
||||
}
|
||||
|
||||
++m_in_packets;
|
||||
|
||||
// this is a valid incoming packet, update the timeout timer
|
||||
|
@ -2664,7 +2708,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
// but the packet is too short
|
||||
if (ptr - buf + 2 > size)
|
||||
{
|
||||
UTP_LOGV("%8p: invalid extension header\n", this);
|
||||
UTP_LOG("%8p: ERROR: invalid extension header\n", this);
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return true;
|
||||
}
|
||||
|
@ -2679,7 +2723,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
}
|
||||
if (ptr - buf + len > size_t(size))
|
||||
{
|
||||
UTP_LOGV("%8p: invalid extension header size:%d packet:%d\n"
|
||||
UTP_LOG("%8p: ERROR: invalid extension header size:%d packet:%d\n"
|
||||
, this, len, int(ptr - buf));
|
||||
m_sm->inc_stats_counter(utp_socket_manager::invalid_pkts_in);
|
||||
return true;
|
||||
|
@ -2708,14 +2752,16 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
// resend the lost packet
|
||||
packet* p = (packet*)m_outbuf.at(m_fast_resend_seq_nr);
|
||||
TORRENT_ASSERT(p);
|
||||
|
||||
// don't fast-resend this again
|
||||
m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK;
|
||||
|
||||
if (p)
|
||||
{
|
||||
experienced_loss(m_fast_resend_seq_nr);
|
||||
resend_packet(p, true);
|
||||
if (m_state == UTP_STATE_ERROR_WAIT || m_state == UTP_STATE_DELETE) return true;
|
||||
}
|
||||
// don't fast-resend this again
|
||||
m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK;
|
||||
}
|
||||
|
||||
// ptr points to the payload of the packet
|
||||
|
@ -2809,7 +2855,7 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
else
|
||||
{
|
||||
#if TORRENT_UTP_LOG
|
||||
UTP_LOGV("%8p: type:%s state:%s (ignored)\n"
|
||||
UTP_LOG("%8p: ERROR: type:%s state:%s (ignored)\n"
|
||||
, this, packet_type_names[ph->get_type()], socket_state_names[m_state]);
|
||||
#endif
|
||||
return true;
|
||||
|
|
Loading…
Reference in New Issue