浏览代码

Update remote_last_win for all ACKs

Only ACKs generated by `dispatch` were updating
`remote_last_win` but not the ACKs generated by
`process`, failing to keep track of the last
announced receive window. This left
`window_to_update` to return false in `dispatch`
after the RX buffer was emptied, thus not announcing
that the receive window is not zero anymore.

The change updates `remote_last_win` for immediate
ACKs generated by `process`.

Closes: #200
Approved by: whitequark
Kai Lüke 7 年之前
父节点
当前提交
7935f0d0b5
共有 1 个文件被更改,包括 62 次插入1 次删除
  1. 62 1
      src/socket/tcp.rs

+ 62 - 1
src/socket/tcp.rs

@@ -782,7 +782,7 @@ impl<'a> TcpSocket<'a> {
         (ip_reply_repr, reply_repr)
     }
 
-    fn ack_reply(&self, ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
+    fn ack_reply(&mut self, ip_repr: &IpRepr, repr: &TcpRepr) -> (IpRepr, TcpRepr<'static>) {
         let (ip_reply_repr, mut reply_repr) = Self::reply(ip_repr, repr);
 
         // From RFC 793:
@@ -792,6 +792,7 @@ impl<'a> TcpSocket<'a> {
         reply_repr.seq_number = self.remote_last_seq;
         reply_repr.ack_number = self.remote_last_ack;
         reply_repr.window_len = self.rx_buffer.window() as u16;
+        self.remote_last_win = reply_repr.window_len;
 
         (ip_reply_repr, reply_repr)
     }
@@ -3340,6 +3341,66 @@ mod test {
         }]);
     }
 
+    #[test]
+    fn test_announce_window_after_read() {
+        let mut s = socket_established();
+        s.rx_buffer = SocketBuffer::new(vec![0; 6]);
+        s.assembler = Assembler::new(s.rx_buffer.capacity());
+        send!(s, TcpRepr {
+            seq_number: REMOTE_SEQ + 1,
+            ack_number: Some(LOCAL_SEQ + 1),
+            payload:    &b"abc"[..],
+            ..SEND_TEMPL
+        });
+        recv!(s, [TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1 + 3),
+            window_len: 3,
+            ..RECV_TEMPL
+        }]);
+        // Test that `dispatch` updates `remote_last_win`
+        assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
+        s.recv(|buffer| {
+            (buffer.len(), ())
+        }).unwrap();
+        assert!(s.window_to_update());
+        recv!(s, [TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1 + 3),
+            window_len: 6,
+            ..RECV_TEMPL
+        }]);
+        assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
+        // Provoke immediate ACK to test that `process` updates `remote_last_win`
+        send!(s, TcpRepr {
+            seq_number: REMOTE_SEQ + 1 + 6,
+            ack_number: Some(LOCAL_SEQ + 1),
+            payload:    &b"def"[..],
+            ..SEND_TEMPL
+        }, Ok(Some(TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1 + 3),
+            window_len: 6,
+            ..RECV_TEMPL
+        })));
+        send!(s, TcpRepr {
+            seq_number: REMOTE_SEQ + 1 + 3,
+            ack_number: Some(LOCAL_SEQ + 1),
+            payload:    &b"abc"[..],
+            ..SEND_TEMPL
+        }, Ok(Some(TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 1 + 9),
+            window_len: 0,
+            ..RECV_TEMPL
+        })));
+        assert_eq!(s.remote_last_win, s.rx_buffer.window() as u16);
+        s.recv(|buffer| {
+            (buffer.len(), ())
+        }).unwrap();
+        assert!(s.window_to_update());
+    }
+
     // =========================================================================================//
     // Tests for timeouts.
     // =========================================================================================//