diff --git a/ChangeLog b/ChangeLog index e10dce742..98ec81fef 100644 --- a/ChangeLog +++ b/ChangeLog @@ -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() diff --git a/src/utp_socket_manager.cpp b/src/utp_socket_manager.cpp index b14c03a54..a760d1b60 100644 --- a/src/utp_socket_manager.cpp +++ b/src/utp_socket_manager.cpp @@ -356,6 +356,8 @@ namespace libtorrent return true; } + if (ph->get_type() == ST_RESET) return false; + // #error send reset return false; diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 822775a94..f24b12db0 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -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;