소스 검색

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

Thanks @pothos for initial analysis of the issue.
whitequark 7 년 전
부모
커밋
b247f6498e
1개의 변경된 파일50개의 추가작업 그리고 0개의 파일을 삭제
  1. 50 0
      src/socket/tcp.rs

+ 50 - 0
src/socket/tcp.rs

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