Przeglądaj źródła

Preserve retransmission timer for Dup-ACKs

Duplicate ACKs should not replace the retransmission timer,
but if not in retransmission, still set the keep-alive timer
as normal ACKs do.
Kai Lüke 7 lat temu
rodzic
commit
86ac32539f
1 zmienionych plików z 40 dodań i 2 usunięć
  1. 40 2
      src/socket/tcp.rs

+ 40 - 2
src/socket/tcp.rs

@@ -159,6 +159,13 @@ impl Timer {
             expires_at: timestamp + CLOSE_DELAY
         }
     }
+
+    fn is_retransmit(&self) -> bool {
+        match *self {
+            Timer::Retransmit {..} => true,
+            _ => false,
+        }
+    }
 }
 
 /// A Transmission Control Protocol socket.
@@ -1025,9 +1032,12 @@ impl<'a> TcpSocket<'a> {
                 self.timer.set_for_idle(timestamp, self.keep_alive);
             }
 
-            // ACK packets in ESTABLISHED state reset the retransmit timer.
+            // ACK packets in ESTABLISHED state reset the retransmit timer,
+            // except for duplicate ACK packets which preserve it.
             (State::Established, TcpControl::None) => {
-                self.timer.set_for_idle(timestamp, self.keep_alive);
+                if !self.timer.is_retransmit() || ack_len != 0 {
+                    self.timer.set_for_idle(timestamp, self.keep_alive);
+                }
             },
 
             // FIN packets in ESTABLISHED state indicate the remote side has closed.
@@ -2889,6 +2899,34 @@ mod test {
         }])
     }
 
+    #[test]
+    fn test_established_retransmit_for_dup_ack() {
+        let mut s = socket_established();
+        // Duplicate ACKs do not replace the retransmission timer
+        s.send_slice(b"abc").unwrap();
+        recv!(s, time 1000, Ok(TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1),
+            payload:    &b"abc"[..],
+            ..RECV_TEMPL
+        }));
+        // Retransmit timer is on because all data was sent
+        assert_eq!(s.tx_buffer.len(), 3);
+        // ACK nothing new
+        send!(s, TcpRepr {
+            seq_number: REMOTE_SEQ + 1,
+            ack_number: Some(LOCAL_SEQ + 1),
+            ..SEND_TEMPL
+        });
+        // Retransmit
+        recv!(s, time 4000, Ok(TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1),
+            payload:    &b"abc"[..],
+            ..RECV_TEMPL
+        }));
+    }
+
     #[test]
     fn test_established_retransmit_reset_after_ack() {
         let mut s = socket_established();