merged uTP fixes from RC_0_16

This commit is contained in:
Arvid Norberg 2013-12-29 19:35:39 +00:00
parent 811def7ae8
commit de6a715092
3 changed files with 78 additions and 27 deletions

View File

@ -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()

View File

@ -356,6 +356,8 @@ namespace libtorrent
return true;
}
if (ph->get_type() == ST_RESET) return false;
// #error send reset
return false;

View File

@ -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;