浏览代码

Do not send window updates in states that shouldn't do so.

Previously, the window update was sent anytime it changed. This is
not desirable for 2 reasons:

- It would send window updates in TimeWait or Closed states, which is incorrect.
- It would send window updates in states where we've already received the
  remote side's FIN, such as CloseWait. This is not necessarily incorrect, but
  is useless, since the remote side is not going to send us more data, therefore
  it's not interested in our window size anymore.
Dario Nieuwenhuis 4 年之前
父节点
当前提交
be6bbfe6d1
共有 1 个文件被更改,包括 59 次插入2 次删除
  1. 59 2
      src/socket/tcp.rs

+ 59 - 2
src/socket/tcp.rs

@@ -1417,8 +1417,11 @@ impl<'a> TcpSocket<'a> {
     }
 
     fn window_to_update(&self) -> bool {
-        (self.rx_buffer.window() >> self.remote_win_shift) as u16 >
-            self.remote_last_win
+        match self.state {
+            State::SynSent | State::SynReceived | State::Established | State::FinWait1 | State::FinWait2 =>
+                (self.rx_buffer.window() >> self.remote_win_shift) as u16 > self.remote_last_win,
+            _ => false,
+        }
     }
 
     pub(crate) fn dispatch<F>(&mut self, timestamp: Instant, caps: &DeviceCapabilities,
@@ -4083,6 +4086,60 @@ mod test {
         }));
     }
 
+    #[test]
+    fn test_close_wait_no_window_update() {
+        let mut s = socket_established();
+        send!(s, TcpRepr {
+            control: TcpControl::Fin,
+            seq_number: REMOTE_SEQ + 1,
+            ack_number: Some(LOCAL_SEQ + 1),
+            payload: &[1,2,3,4],
+            ..SEND_TEMPL
+        });
+        assert_eq!(s.state, State::CloseWait);
+
+        // we ack the FIN, with the reduced window size.
+        recv!(s, Ok(TcpRepr {
+            seq_number: LOCAL_SEQ + 1,
+            ack_number: Some(REMOTE_SEQ + 6),
+            window_len: 60,
+            ..RECV_TEMPL
+        }));
+
+        let rx_buf = &mut [0; 32];
+        assert_eq!(s.recv_slice(rx_buf), Ok(4));
+
+        // check that we do NOT send a window update even if it has changed.
+        recv!(s, Err(Error::Exhausted));
+    }
+
+    #[test]
+    fn test_time_wait_no_window_update() {
+        let mut s = socket_fin_wait_2();
+        send!(s, TcpRepr {
+            control: TcpControl::Fin,
+            seq_number: REMOTE_SEQ + 1,
+            ack_number: Some(LOCAL_SEQ + 2),
+            payload: &[1,2,3,4],
+            ..SEND_TEMPL
+        });
+        assert_eq!(s.state, State::TimeWait);
+
+        // we ack the FIN, with the reduced window size.
+        recv!(s, Ok(TcpRepr {
+            seq_number: LOCAL_SEQ + 2,
+            ack_number: Some(REMOTE_SEQ + 6),
+            window_len: 60,
+            ..RECV_TEMPL
+        }));
+
+        let rx_buf = &mut [0; 32];
+        assert_eq!(s.recv_slice(rx_buf), Ok(4));
+
+        // check that we do NOT send a window update even if it has changed.
+        recv!(s, Err(Error::Exhausted));
+    }
+
     // =========================================================================================//
     // Tests for flow control.
     // =========================================================================================//