Correctly handle retransmission of lost-received-lost TCP segments.

Thanks @pothos for initial analysis of the issue.
This commit is contained in:
whitequark 2017-12-22 19:31:04 +00:00
parent ae17151f2a
commit 436f4ef624
1 changed files with 50 additions and 0 deletions

View File

@ -1123,6 +1123,14 @@ impl<'a> TcpSocket<'a> {
// We've processed everything in the incoming segment, so advance the local
// sequence number past it.
self.local_seq_no = ack_number;
// During retransmission, if an earlier segment got lost but later was
// successfully received, self.local_seq_no can move past self.remote_last_seq.
// Do not attempt to retransmit the latter segments; not only this is pointless
// in theory but also impossible in practice, since they have been already
// deallocated from the buffer.
if self.remote_last_seq < self.local_seq_no {
self.remote_last_seq = self.local_seq_no
}
}
let payload_len = repr.payload.len();
@ -2991,6 +2999,48 @@ mod test {
}));
}
#[test]
fn test_established_queue_during_retransmission() {
let mut s = socket_established();
s.remote_mss = 6;
s.send_slice(b"abcdef123456ABCDEF").unwrap();
recv!(s, time 1000, Ok(TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1),
payload: &b"abcdef"[..],
..RECV_TEMPL
})); // this one is dropped
recv!(s, time 1005, Ok(TcpRepr {
seq_number: LOCAL_SEQ + 1 + 6,
ack_number: Some(REMOTE_SEQ + 1),
payload: &b"123456"[..],
..RECV_TEMPL
})); // this one is received
recv!(s, time 1010, Ok(TcpRepr {
seq_number: LOCAL_SEQ + 1 + 6 + 6,
ack_number: Some(REMOTE_SEQ + 1),
payload: &b"ABCDEF"[..],
..RECV_TEMPL
})); // also dropped
recv!(s, time 2000, Ok(TcpRepr {
seq_number: LOCAL_SEQ + 1,
ack_number: Some(REMOTE_SEQ + 1),
payload: &b"abcdef"[..],
..RECV_TEMPL
})); // retransmission
send!(s, time 2005, TcpRepr {
seq_number: REMOTE_SEQ + 1,
ack_number: Some(LOCAL_SEQ + 1 + 6 + 6),
..SEND_TEMPL
}); // acknowledgement of both segments
recv!(s, time 2010, Ok(TcpRepr {
seq_number: LOCAL_SEQ + 1 + 6 + 6,
ack_number: Some(REMOTE_SEQ + 1),
payload: &b"ABCDEF"[..],
..RECV_TEMPL
})); // retransmission of only unacknowledged data
}
#[test]
fn test_close_wait_retransmit_reset_after_ack() {
let mut s = socket_close_wait();