Explorar o código

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 %!s(int64=4) %!d(string=hai) anos
pai
achega
be6bbfe6d1
Modificáronse 1 ficheiros con 59 adicións e 2 borrados
  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.
     // =========================================================================================//