mirror of
https://github.com/smoltcp-rs/smoltcp.git
synced 2025-10-01 23:01:11 +00:00
Don't delay ACKs for significant window updates
This commit is contained in:
parent
ef67e7b46c
commit
fe179c9184
@ -656,7 +656,6 @@ impl<'a> Socket<'a> {
|
||||
/// Return the current window field value, including scaling according to RFC 1323.
|
||||
///
|
||||
/// Used in internal calculations as well as packet generation.
|
||||
///
|
||||
#[inline]
|
||||
fn scaled_window(&self) -> u16 {
|
||||
cmp::min(
|
||||
@ -665,6 +664,25 @@ impl<'a> Socket<'a> {
|
||||
) as u16
|
||||
}
|
||||
|
||||
/// Return the last window field value, including scaling according to RFC 1323.
|
||||
///
|
||||
/// Used in internal calculations as well as packet generation.
|
||||
///
|
||||
/// Unlike `remote_last_win`, we take into account new packets received (but not acknowledged)
|
||||
/// since the last window update and adjust the window length accordingly. This ensures a fair
|
||||
/// comparison between the last window length and the new window length we're going to
|
||||
/// advertise.
|
||||
#[inline]
|
||||
fn last_scaled_window(&self) -> Option<u16> {
|
||||
let last_ack = self.remote_last_ack?;
|
||||
let next_ack = self.remote_seq_no + self.rx_buffer.len();
|
||||
|
||||
let last_win = (self.remote_last_win as usize) << self.remote_win_shift;
|
||||
let last_win_adjusted = last_ack + last_win - next_ack;
|
||||
|
||||
Some(cmp::min(last_win_adjusted >> self.remote_win_shift, (1 << 16) - 1) as u16)
|
||||
}
|
||||
|
||||
/// Set the timeout duration.
|
||||
///
|
||||
/// A socket with a timeout duration set will abort the connection if either of the following
|
||||
@ -2130,13 +2148,26 @@ impl<'a> Socket<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Return whether we should send ACK immediately due to significant window updates.
|
||||
///
|
||||
/// ACKs with significant window updates should be sent immediately to let the sender know that
|
||||
/// more data can be sent. According to the Linux kernel implementation, "significant" means
|
||||
/// doubling the receive window. The Linux kernel implementation can be found at
|
||||
/// <https://elixir.bootlin.com/linux/v6.9.9/source/net/ipv4/tcp.c#L1472>.
|
||||
fn window_to_update(&self) -> bool {
|
||||
match self.state {
|
||||
State::SynSent
|
||||
| State::SynReceived
|
||||
| State::Established
|
||||
| State::FinWait1
|
||||
| State::FinWait2 => self.scaled_window() > self.remote_last_win,
|
||||
| State::FinWait2 => {
|
||||
let new_win = self.scaled_window();
|
||||
if let Some(last_win) = self.last_scaled_window() {
|
||||
new_win > 0 && new_win / 2 >= last_win
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -2202,7 +2233,7 @@ impl<'a> Socket<'a> {
|
||||
} else if self.ack_to_transmit() && self.delayed_ack_expired(cx.now()) {
|
||||
// If we have data to acknowledge, do it.
|
||||
tcp_trace!("outgoing segment will acknowledge");
|
||||
} else if self.window_to_update() && self.delayed_ack_expired(cx.now()) {
|
||||
} else if self.window_to_update() {
|
||||
// If we have window length increase to advertise, do it.
|
||||
tcp_trace!("outgoing segment will update window");
|
||||
} else if self.state == State::Closed {
|
||||
@ -2452,8 +2483,11 @@ impl<'a> Socket<'a> {
|
||||
} else if self.seq_to_transmit(cx) {
|
||||
// We have a data or flag packet to transmit.
|
||||
PollAt::Now
|
||||
} else if self.window_to_update() {
|
||||
// The receive window has been raised significantly.
|
||||
PollAt::Now
|
||||
} else {
|
||||
let want_ack = self.ack_to_transmit() || self.window_to_update();
|
||||
let want_ack = self.ack_to_transmit();
|
||||
|
||||
let delayed_ack_poll_at = match (want_ack, self.ack_delay_timer) {
|
||||
(false, _) => PollAt::Ingress,
|
||||
@ -2785,7 +2819,7 @@ mod test {
|
||||
s.local_seq_no = LOCAL_SEQ + 1;
|
||||
s.remote_last_seq = LOCAL_SEQ + 1;
|
||||
s.remote_last_ack = Some(REMOTE_SEQ + 1);
|
||||
s.remote_last_win = 64;
|
||||
s.remote_last_win = s.scaled_window();
|
||||
s
|
||||
}
|
||||
|
||||
@ -6325,6 +6359,63 @@ mod test {
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_update_with_delay_ack() {
|
||||
let mut s = socket_established_with_buffer_sizes(6, 6);
|
||||
s.ack_delay = Some(Duration::from_millis(10));
|
||||
|
||||
send!(
|
||||
s,
|
||||
TcpRepr {
|
||||
seq_number: REMOTE_SEQ + 1,
|
||||
ack_number: Some(LOCAL_SEQ + 1),
|
||||
payload: &b"abcdef"[..],
|
||||
..SEND_TEMPL
|
||||
}
|
||||
);
|
||||
|
||||
recv_nothing!(s, time 5);
|
||||
|
||||
s.recv(|buffer| {
|
||||
assert_eq!(&buffer[..2], b"ab");
|
||||
(2, ())
|
||||
})
|
||||
.unwrap();
|
||||
recv!(
|
||||
s,
|
||||
time 5,
|
||||
Ok(TcpRepr {
|
||||
seq_number: LOCAL_SEQ + 1,
|
||||
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
||||
window_len: 2,
|
||||
..RECV_TEMPL
|
||||
})
|
||||
);
|
||||
|
||||
s.recv(|buffer| {
|
||||
assert_eq!(&buffer[..1], b"c");
|
||||
(1, ())
|
||||
})
|
||||
.unwrap();
|
||||
recv_nothing!(s, time 5);
|
||||
|
||||
s.recv(|buffer| {
|
||||
assert_eq!(&buffer[..1], b"d");
|
||||
(1, ())
|
||||
})
|
||||
.unwrap();
|
||||
recv!(
|
||||
s,
|
||||
time 5,
|
||||
Ok(TcpRepr {
|
||||
seq_number: LOCAL_SEQ + 1,
|
||||
ack_number: Some(REMOTE_SEQ + 1 + 6),
|
||||
window_len: 4,
|
||||
..RECV_TEMPL
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fill_peer_window() {
|
||||
let mut s = socket_established();
|
||||
|
Loading…
x
Reference in New Issue
Block a user