From 48a7ab13d5eb23acbe092a6b1d0eab2684337cc0 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 31 Dec 2018 16:11:50 +0100 Subject: [PATCH 1/5] improve utp verbose logging a bit and make the parser pull out more metrics --- src/utp_stream.cpp | 25 +++++----- tools/parse_utp_log.py | 101 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 48388cff7..8beb7f2dc 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -739,7 +739,7 @@ void utp_init_mtu(utp_socket_impl* s, int link_mtu, int utp_mtu) } bool utp_incoming_packet(utp_socket_impl* s, char const* p - , int size, udp::endpoint const& ep, time_point receive_time) + , int size, udp::endpoint const& ep, time_point const receive_time) { return s->incoming_packet(reinterpret_cast(p), size , ep, receive_time); @@ -1120,8 +1120,8 @@ size_t utp_stream::read_some(bool clear_buffers) if (m_impl->m_receive_buffer_size == 0) { - UTP_LOGV(" Didn't fill entire target: %d bytes left in buffer\n" - , m_impl->m_receive_buffer_size); + UTP_LOGV("%8p: Didn't fill entire target: %d bytes left in buffer\n" + , static_cast(m_impl), m_impl->m_receive_buffer_size); break; } } @@ -1509,8 +1509,8 @@ void utp_socket_impl::parse_close_reason(boost::uint8_t const* ptr, int size) utp_stream::on_close_reason(m_userdata, incoming_close_reason); } -void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr - , int size, int* acked_bytes, time_point const now, boost::uint32_t& min_rtt) +void utp_socket_impl::parse_sack(boost::uint16_t const packet_ack, boost::uint8_t const* ptr + , int const size, int* acked_bytes, time_point const now, boost::uint32_t& min_rtt) { INVARIANT_CHECK; @@ -1917,7 +1917,6 @@ bool utp_socket_impl::send_pkt(int const flags) p = reinterpret_cast(TORRENT_ALLOCA(char, sizeof(packet) + packet_size + sizeof(packet*) - 1)); p = reinterpret_cast(align_pointer(p)); - UTP_LOGV("%8p: allocating %d bytes on the stack\n", static_cast(this), packet_size); p->allocated = packet_size; } @@ -1976,8 +1975,11 @@ bool utp_socket_impl::send_pkt(int const flags) write_payload(p->buf + p->size, size_left); p->size += size_left; - UTP_LOGV("%8p: NAGLE appending %d bytes to nagle packet. new size: %d allocated: %d\n" - , static_cast(this), size_left, p->size, p->allocated); + if (size_left > 0) + { + UTP_LOGV("%8p: NAGLE appending %d bytes to nagle packet. new size: %d allocated: %d\n" + , static_cast(this), size_left, p->size, p->allocated); + } // did we fill up the whole mtu? // if we didn't, we may still send it if there's @@ -2352,7 +2354,8 @@ void utp_socket_impl::experienced_loss(int const seq_nr) { m_ssthres = m_cwnd >> 16; m_slow_start = false; - UTP_LOGV("%8p: experienced loss, slow_start -> 0\n", static_cast(this)); + UTP_LOGV("%8p: experienced loss, slow_start -> 0 ssthres:%d\n" + , static_cast(this), m_ssthres); } } @@ -2533,7 +2536,7 @@ bool utp_socket_impl::cancel_handlers(error_code const& ec, bool kill) bool utp_socket_impl::consume_incoming_data( utp_header const* ph, boost::uint8_t const* ptr, int payload_size - , time_point now) + , time_point const now) { INVARIANT_CHECK; @@ -3566,7 +3569,7 @@ int utp_socket_impl::packet_timeout() const return timeout; } -void utp_socket_impl::tick(time_point now) +void utp_socket_impl::tick(time_point const now) { INVARIANT_CHECK; diff --git a/tools/parse_utp_log.py b/tools/parse_utp_log.py index 179a03e13..c302b3991 100755 --- a/tools/parse_utp_log.py +++ b/tools/parse_utp_log.py @@ -69,19 +69,30 @@ metrics = { 'cur_window_packets':['number of packets in-flight', 'x1y2', 'steps'], 'packet_size':['current packet size (B)', 'x1y2', 'steps'], 'rtt':['rtt (ms)', 'x1y2', rtt], + 'min_rtt':['smallest rtt (ms)', 'x1y2', 'lines'], 'off_target':['off-target (ms)', 'x1y2', off_target], 'delay_sum':['delay sum (ms)', 'x1y2', 'steps'], 'their_delay':['their delay (ms)', 'x1y2', delay_samples], 'get_microseconds':['clock (us)', 'x1y1', 'steps'], 'wnduser':['advertised window size (B)', 'x1y1', 'steps'], 'ssthres':['slow-start threshold (B)', 'x1y1', 'steps'], + 'timeout':['until next timeout (ms)', 'x1y2', 'steps'], + 'rto':['current timeout (ms)', 'x1y2', 'steps'], 'delay_base':['delay base (us)', 'x1y1', delay_base], 'their_delay_base':['their delay base (us)', 'x1y1', delay_base], 'their_actual_delay':['their actual delay (us)', 'x1y1', delay_samples], 'actual_delay':['actual_delay (us)', 'x1y1', delay_samples], 'send_buffer':['send buffer size (B)', 'x1y1', send_buffer], - 'recv_buffer':['receive buffer size (B)', 'x1y1', 'lines'] + 'recv_buffer':['receive buffer size (B)', 'x1y1', 'lines'], + 'packet_loss':['packet lost', 'x1y2', 'steps'], + 'packet_timeout':['packet timed out', 'x1y2', 'steps'], + 'acked_bytes':['Bytes ACKed by packet', 'x1y2', 'steps'], + 'bytes_sent':['cumulative bytes sent', 'x1y2', 'steps'], + 'bytes_resent':['cumulative bytes resent', 'x1y2', 'steps'], + 'written':['reported written bytes', 'x1y2', 'steps'], + 'ack_nr':['acked sequence number', 'x1y2', 'steps'], + 'seq_nr':['sent sequence number', 'x1y2', 'steps'], } histogram_quantization = 1 @@ -94,10 +105,14 @@ begin = None title = "-" packet_loss = 0 packet_timeout = 0 +num_acked = 0 delay_histogram = {} packet_size_histogram = {} window_size = {'0': 0, '1': 0} +bytes_sent = 0 +bytes_resent = 0 +written = 0 # [35301484] 0x00ec1190: actual_delay:1021583 our_delay:102 their_delay:-1021345 off_target:297 max_window:2687 upload_rate:18942 delay_base:1021481154 delay_sum:-1021242 target_delay:400 acked_bytes:1441 cur_window:2882 scaled_gain:2.432 @@ -131,15 +146,34 @@ for l in file: print "\r%d " % counter, if "lost." in l: - packet_loss = packet_loss + 1 + packet_loss += 1 continue - if "Packet timeout" in l: - packet_timeout = packet_timeout + 1 + if "lost (timeout)" in l: + packet_timeout += 1 continue + if "acked packet " in l: + num_acked += 1 if "sending packet" in l: v = l.split('size:')[1].split(' ')[0] packet_size_histogram[v] = 1 + packet_size_histogram.get(v, 0) + bytes_sent += int(v) + + if "re-sending packet" in l: + v = l.split('size:')[1].split(' ')[0] + bytes_resent += int(v) + + if 'calling write handler' in l: + v = l.split('written:')[1].split(' ')[0] + written += int(v) + + if "incoming packet" in l \ + and not "ERROR" in l \ + and "seq_nr:" in l \ + and "type:ST_SYN" not in l: + if "ack_nr:" not in l: print l + ack_nr = int(l.split('ack_nr:')[1].split(' ')[0]) + seq_nr = int(l.split('seq_nr:')[1].split(' ')[0]) if "our_delay:" not in l: continue @@ -184,9 +218,14 @@ for l in file: print >>out, '%f\t' % int(reduce(lambda a,b: a+b, window_size.values())), else: print >>out, '%f\t' % v, - print >>out, float(packet_loss * 8000), float(packet_timeout * 8000) + + if fill_columns: + columns += ['packet_loss', 'packet_timeout', 'bytes_sent', 'ack_nr', 'seq_nr', 'bytes_resent', 'written'] + print >>out, float(packet_loss), float(packet_timeout), float(bytes_sent), ack_nr, seq_nr, float(bytes_resent), written packet_loss = 0 packet_timeout = 0 + num_acked = 0; + written = 0 out.close() @@ -207,6 +246,12 @@ plot = [ 'y1': 'Bytes', 'y2': 'Time (ms)' }, + { + 'data': ['max_window', 'send_buffer', 'cur_window', 'written'], + 'title': 'bytes-written', + 'y1': 'Bytes', + 'y2': 'Time (ms)' + }, { 'data': ['upload_rate', 'max_window', 'cur_window', 'wnduser', 'cur_window_packets', 'packet_size', 'rtt'], 'title': 'slow-start', @@ -219,6 +264,30 @@ plot = [ 'y1': 'Bytes', 'y2': 'Time (ms)' }, + { + 'data': ['max_window', 'cur_window', 'packet_loss'], + 'title': 'packet-loss', + 'y1': 'Bytes', + 'y2': 'count' + }, + { + 'data': ['max_window', 'cur_window', 'packet_timeout'], + 'title': 'packet-timeout', + 'y1': 'Bytes', + 'y2': 'count' + }, + { + 'data': ['max_window', 'cur_window', 'bytes_sent', 'bytes_resent'], + 'title': 'cumulative-bytes-sent', + 'y1': 'Bytes', + 'y2': 'Cumulative Bytes' + }, + { + 'data': ['max_window', 'cur_window', 'rto', 'timeout'], + 'title': 'connection-timeout', + 'y1': 'Bytes', + 'y2': 'Time (ms)' + }, { 'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'wnduser', 'cur_window_packets'], 'title': 'uploading', @@ -227,33 +296,45 @@ plot = [ }, { 'data': ['our_delay', 'max_window', 'target_delay', 'cur_window', 'send_buffer'], - 'title': 'uploading_packets', + 'title': 'uploading-packets', 'y1': 'Bytes', 'y2': 'Time (ms)' }, { 'data': ['their_delay', 'target_delay', 'rtt'], - 'title': 'their_delay', + 'title': 'their-delay', 'y1': '', 'y2': 'Time (ms)' }, { 'data': ['their_actual_delay','their_delay_base'], - 'title': 'their_delay_base', + 'title': 'their-delay-base', 'y1': 'Time (us)', 'y2': '' }, { - 'data': ['our_delay', 'target_delay', 'rtt'], + 'data': ['our_delay', 'target_delay', 'rtt', 'min_rtt'], 'title': 'our-delay', 'y1': '', 'y2': 'Time (ms)' }, { 'data': ['actual_delay', 'delay_base'], - 'title': 'our_delay_base', + 'title': 'our-delay-base', 'y1': 'Time (us)', 'y2': '' + }, + { + 'data': ['ack_nr', 'seq_nr'], + 'title': 'sequence-numbers', + 'y1': 'Bytes', + 'y2': 'seqnr' + }, + { + 'data': ['max_window', 'cur_window', 'acked_bytes'], + 'title': 'ack-rate', + 'y1': 'Bytes', + 'y2': 'Bytes' } ] From 6f1f4668323f5e88ff85ea1779900bc35cb70ca7 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 31 Dec 2018 15:50:12 +0100 Subject: [PATCH 2/5] improve logic for fast-retransmitting packets on incoming SACK --- src/utp_stream.cpp | 114 +++++++++++++++++++++++++++++++-------------- 1 file changed, 80 insertions(+), 34 deletions(-) diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 8beb7f2dc..0dfbbdc53 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -1533,40 +1533,37 @@ void utp_socket_impl::parse_sack(boost::uint16_t const packet_ack, boost::uint8_ mask <<= 1; } } - UTP_LOGV("%8p: got SACK first:%d %s our_seq_nr:%u\n" - , static_cast(this), ack_nr, bitmask.c_str(), m_seq_nr); + UTP_LOGV("%8p: got SACK first:%d %s our_seq_nr:%u fast_resend_seq_nr:%d\n" + , static_cast(this), ack_nr, bitmask.c_str(), m_seq_nr, m_fast_resend_seq_nr); #endif - // the number of acked packets past the fast re-send sequence number - // this is used to determine if we should trigger more fast re-sends - int dups = 0; + boost::array resend; + int num_to_resend = 0; - // the sequence number of the last ACKed packet - int last_ack = packet_ack; + // this was implicitly lost + + if (!compare_less_wrap((packet_ack + 1) & ACK_MASK, m_fast_resend_seq_nr, ACK_MASK)) + { + resend[num_to_resend++] = (packet_ack + 1) & ACK_MASK; + } // for each byte - for (boost::uint8_t const* end = ptr + size; ptr != end; ++ptr) + boost::uint8_t const* const start = ptr; + boost::uint8_t const* const end = ptr + size; + for (; ptr != end; ++ptr) { - unsigned char bitfield = unsigned(*ptr); + unsigned char const bitfield = unsigned(*ptr); unsigned char mask = 1; // for each bit for (int i = 0; i < 8; ++i) { if (mask & bitfield) { - last_ack = ack_nr; - if (m_fast_resend_seq_nr == ack_nr) - m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK; - - if (compare_less_wrap(m_fast_resend_seq_nr, ack_nr, ACK_MASK)) ++dups; // this bit was set, ack_nr was received packet* p = m_outbuf.remove(ack_nr); if (p) { *acked_bytes += p->size - p->header_size; - // each ACKed packet counts as a duplicate ack - UTP_LOGV("%8p: duplicate_acks:%u fast_resend_seq_nr:%u\n" - , static_cast(this), m_duplicate_acks, m_fast_resend_seq_nr); ack_packet(p, now, min_rtt, ack_nr); } else @@ -1576,6 +1573,11 @@ void utp_socket_impl::parse_sack(boost::uint16_t const packet_ack, boost::uint8_ maybe_inc_acked_seq_nr(); } } + else if (!compare_less_wrap(ack_nr, m_fast_resend_seq_nr, ACK_MASK) + && num_to_resend < resend.size()) + { + resend[num_to_resend++] = ack_nr; + } mask <<= 1; ack_nr = (ack_nr + 1) & ACK_MASK; @@ -1588,30 +1590,74 @@ void utp_socket_impl::parse_sack(boost::uint16_t const packet_ack, boost::uint8_ if (ack_nr == m_seq_nr) break; } + // 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 + // bitmask + int last_resend = (packet_ack + 1 + size * 8) & ACK_MASK; + + // the number of acked packets past the fast re-send sequence number + // this is used to determine if we should trigger more fast re-sends + int dups = 0; + + for (boost::uint8_t const* i = end; i != start; --i) + { + unsigned char const bitfield = unsigned(i[-1]); + unsigned char mask = 0x80; + // for each bit + for (int k = 0; k < 8; ++k) + { + if (mask & bitfield) ++dups; + if (dups > dup_ack_limit) break; + last_resend = (last_resend - 1) & ACK_MASK; + mask >>= 1; + } + if (dups > dup_ack_limit) break; + } + + // we did not get enough packets acked in this message to warrant a resend + if (dups <= dup_ack_limit) + { + UTP_LOGV("%8p: only %d ACKs in SACK, requires more than %d to trigger fast retransmit\n" + , static_cast(this), dups, dup_ack_limit); + num_to_resend = 0; + } + + // now we need to (likely) prune the tail of the resend list, since all + // "unacked" packets that weren't followed by an acked one, don't count + while (num_to_resend > 0 && !compare_less_wrap(resend[num_to_resend - 1], last_resend, ACK_MASK)) + { + --num_to_resend; + } + TORRENT_ASSERT(m_outbuf.at((m_acked_seq_nr + 1) & ACK_MASK) || ((m_seq_nr - m_acked_seq_nr) & ACK_MASK) <= 1); - // we received more than dup_ack_limit ACKs in this SACK message. - // trigger fast re-send - if (dups >= dup_ack_limit && compare_less_wrap(m_fast_resend_seq_nr, last_ack, ACK_MASK)) - { - experienced_loss(m_fast_resend_seq_nr); - int num_resent = 0; + bool cut_cwnd = true; - // only re-sending a single packet per sack - // appears to improve performance by making it - // less likely to loose the re-sent packet. Because - // when that happens, we must time-out in order - // to continue, which takes a long time. - if (m_fast_resend_seq_nr != last_ack) + // we received more than dup_ack_limit ACKs in this SACK message. + // trigger fast re-send. This is not an equal check because 3 identical ACKS + // are only 2 duplicates + for (int i = 0; i < num_to_resend; ++i) + { + boost::uint16_t const pkt_seq = resend[i]; + + packet* p = m_outbuf.at(pkt_seq); + UTP_LOGV("%8p: Packet %d lost. (fast_resend_seq_nr:%d trigger fast-resend)\n" + , static_cast(this), pkt_seq, m_fast_resend_seq_nr); + if (p) { - packet* p = m_outbuf.at(m_fast_resend_seq_nr); - m_fast_resend_seq_nr = (m_fast_resend_seq_nr + 1) & ACK_MASK; - if (p) + if (resend_packet(p, true)) { - ++num_resent; - if (resend_packet(p, true)) m_duplicate_acks = 0; + m_duplicate_acks = 0; + m_fast_resend_seq_nr = (pkt_seq + 1) & ACK_MASK; } } + + if (cut_cwnd) + { + experienced_loss(pkt_seq); + cut_cwnd = false; + } } } From 8ffd524b5fe184f1548f8d1f22add5833839d339 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 31 Dec 2018 15:28:43 +0100 Subject: [PATCH 3/5] simplify and improve the uTP deferred ACK logic to respond earlier --- ChangeLog | 2 ++ include/libtorrent/utp_socket_manager.hpp | 9 ++++----- src/utp_socket_manager.cpp | 24 +++++++++++++---------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index e903bdcc1..ca313791c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ + * uTP performance fixes + 1.1.11 release * fix move_storage with save_path with a trailing slash diff --git a/include/libtorrent/utp_socket_manager.hpp b/include/libtorrent/utp_socket_manager.hpp index 487175fcb..8865fbd2f 100644 --- a/include/libtorrent/utp_socket_manager.hpp +++ b/include/libtorrent/utp_socket_manager.hpp @@ -121,11 +121,10 @@ namespace libtorrent typedef std::multimap socket_map_t; socket_map_t m_utp_sockets; - // this is a list of sockets that needs to send an ack. - // once the UDP socket is drained, all of these will - // have a chance to do that. This is to avoid sending - // an ack for every single packet - std::vector m_deferred_acks; + // if this is set, it means this socket still needs to send an ACK. Once + // we exit the loop processing packets, or switch to processing packets + // for a different socket, issue the ACK packet and clear this. + utp_socket_impl* m_deferred_ack; // sockets that have received or sent packets this // round, may subscribe to the event of draining the diff --git a/src/utp_socket_manager.cpp b/src/utp_socket_manager.cpp index 358b697b0..2346eea90 100644 --- a/src/utp_socket_manager.cpp +++ b/src/utp_socket_manager.cpp @@ -53,6 +53,7 @@ namespace libtorrent , incoming_utp_callback_t cb) : m_sock(s) , m_cb(cb) + , m_deferred_ack(0) , m_last_socket(0) , m_new_connection(-1) , m_sett(sett) @@ -268,6 +269,12 @@ namespace libtorrent return utp_incoming_packet(m_last_socket, p, size, ep, receive_time); } + if (m_deferred_ack) + { + utp_send_ack(m_deferred_ack); + m_deferred_ack = NULL; + } + std::pair r = m_utp_sockets.equal_range(id); @@ -319,6 +326,7 @@ namespace libtorrent utp_init_mtu(str->get_impl(), link_mtu, utp_mtu); bool ret = utp_incoming_packet(str->get_impl(), p, size, ep, receive_time); if (!ret) return false; + m_last_socket = str->get_impl(); m_cb(c); // the connection most likely changed its connection ID here // we need to move it to the correct ID @@ -353,14 +361,10 @@ namespace libtorrent void utp_socket_manager::socket_drained() { - // flush all deferred acks - - std::vector deferred_acks; - m_deferred_acks.swap(deferred_acks); - for (std::vector::iterator i = deferred_acks.begin() - , end(deferred_acks.end()); i != end; ++i) + if (m_deferred_ack) { - utp_socket_impl* s = *i; + utp_socket_impl* s = m_deferred_ack; + m_deferred_ack = NULL; utp_send_ack(s); } @@ -376,9 +380,8 @@ namespace libtorrent void utp_socket_manager::defer_ack(utp_socket_impl* s) { - TORRENT_ASSERT(std::find(m_deferred_acks.begin(), m_deferred_acks.end(), s) - == m_deferred_acks.end()); - m_deferred_acks.push_back(s); + TORRENT_ASSERT(m_deferred_ack == NULL || m_deferred_ack == s); + m_deferred_ack = s; } void utp_socket_manager::subscribe_drained(utp_socket_impl* s) @@ -394,6 +397,7 @@ namespace libtorrent if (i == m_utp_sockets.end()) return; delete_utp_impl(i->second); if (m_last_socket == i->second) m_last_socket = 0; + if (m_deferred_ack == i->second) m_deferred_ack = 0; m_utp_sockets.erase(i); } From ee1e66e851f6ee4e4337c2141f0327fcedc402e9 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 31 Dec 2018 15:18:22 +0100 Subject: [PATCH 4/5] don't leave slow-start just because we hit the advertized receive window. uTorrent adjusts its receive window dynamically which may just cause a temporary restriction --- src/utp_stream.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index 0dfbbdc53..b4915135b 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -3577,13 +3577,15 @@ void utp_socket_impl::do_ledbat(const int acked_bytes, const int delay , static_cast(this), m_mtu, in_flight, int(m_adv_wnd), int(m_cwnd >> 16), acked_bytes); m_cwnd_full = false; } - +/* if ((m_cwnd >> 16) >= m_adv_wnd) { m_slow_start = false; + m_ssthres = (m_cwnd >> 16); UTP_LOGV("%8p: cwnd > advertized wnd (%d) slow_start -> 0\n" , static_cast(this), m_adv_wnd); } +*/ } void utp_stream::bind(endpoint_type const&, error_code&) { } From a81eb050c5d55446ba6a7a583200503793447658 Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 31 Dec 2018 15:37:54 +0100 Subject: [PATCH 5/5] remove old (incompatible) sequence number build option --- src/utp_stream.cpp | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index b4915135b..1851bc620 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -44,10 +44,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -// the behavior of the sequence numbers as implemented by uTorrent is not -// particularly regular. This switch indicates the odd parts. -#define TORRENT_UT_SEQ 1 - #if TORRENT_UTP_LOG #include #include "libtorrent/socket_io.hpp" @@ -350,7 +346,7 @@ struct utp_socket_impl void parse_close_reason(boost::uint8_t const* ptr, int size); void write_payload(boost::uint8_t* ptr, int size); void maybe_inc_acked_seq_nr(); - void ack_packet(packet* p, time_point const& receive_time + void ack_packet(packet* p, time_point receive_time , boost::uint32_t& min_rtt, boost::uint16_t seq_nr); void write_sack(boost::uint8_t* buf, int size) const; void incoming(boost::uint8_t const* buf, int size, packet* p, time_point now); @@ -2188,12 +2184,6 @@ bool utp_socket_impl::send_pkt(int const flags) // be a nagle packet waiting for more data TORRENT_ASSERT(m_nagle_packet == NULL); -#if !TORRENT_UT_SEQ - // if the other end closed the connection immediately - // our FIN packet will end up having the same sequence - // number as the SYN, so this assert is invalid - TORRENT_ASSERT(!m_outbuf.at(m_seq_nr)); -#endif TORRENT_ASSERT(h->seq_nr == m_seq_nr); // 0 is a special sequence number, since it's also used as "uninitialized". @@ -2447,8 +2437,8 @@ void utp_socket_impl::maybe_inc_acked_seq_nr() m_duplicate_acks = 0; } -void utp_socket_impl::ack_packet(packet* p, time_point const& receive_time - , boost::uint32_t& min_rtt, boost::uint16_t seq_nr) +void utp_socket_impl::ack_packet(packet* p, time_point const receive_time + , boost::uint32_t& min_rtt, boost::uint16_t const seq_nr) { #ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS INVARIANT_CHECK; @@ -2471,7 +2461,6 @@ void utp_socket_impl::ack_packet(packet* p, time_point const& receive_time TORRENT_ASSERT(p->mtu_probe); // our mtu probe was acked! m_mtu_floor = (std::max)(m_mtu_floor, p->size); - if (m_mtu_ceiling < m_mtu_floor) m_mtu_ceiling = m_mtu_floor; update_mtu_limits(); } @@ -2857,11 +2846,10 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size // something is wrong. // If our state is state_none, this packet must be a syn packet // and the ack_nr should be ignored - boost::uint16_t cmp_seq_nr = (m_seq_nr - 1) & ACK_MASK; -#if TORRENT_UT_SEQ - if (m_state == UTP_STATE_SYN_SENT && ph->get_type() == ST_STATE) - cmp_seq_nr = m_seq_nr; -#endif + boost::uint16_t const cmp_seq_nr = + (m_state == UTP_STATE_SYN_SENT && ph->get_type() == ST_STATE) + ? m_seq_nr : (m_seq_nr - 1) & ACK_MASK; + if ((m_state != UTP_STATE_NONE || ph->get_type() != ST_SYN) && (compare_less_wrap(cmp_seq_nr, ph->ack_nr, ACK_MASK) || compare_less_wrap(ph->ack_nr, m_acked_seq_nr @@ -2899,7 +2887,9 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size // if the socket is closing, always ignore any packet // 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)) + // ST_STATE messages always include the next seqnr. + if (m_eof && (compare_less_wrap(m_eof_seq_nr, ph->seq_nr, ACK_MASK) + || (m_eof_seq_nr == ph->seq_nr && ph->get_type() != ST_STATE))) { #if TORRENT_UTP_LOG UTP_LOG("%8p: ERROR: incoming packet type: %s seq_nr:%d eof_seq_nr:%d (ignored)\n" @@ -3680,7 +3670,6 @@ void utp_socket_impl::tick(time_point const now) // we had was the probe. Assume it was dropped // because it was too big m_mtu_ceiling = m_mtu - 1; - if (m_mtu_floor > m_mtu_ceiling) m_mtu_floor = m_mtu_ceiling; update_mtu_limits(); }