Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add the retry time interval for sending syn messages #854

Closed
wants to merge 14 commits into from
62 changes: 54 additions & 8 deletions src/socket/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,11 @@ enum Timer {
Idle {
keep_alive_at: Option<Instant>,
},
SynRetransmit {
expires_at: Instant,
delay: Duration,
retries: u8,
},
Retransmit {
expires_at: Instant,
delay: Duration,
Expand All @@ -265,6 +270,7 @@ enum Timer {

const ACK_DELAY_DEFAULT: Duration = Duration::from_millis(10);
const CLOSE_DELAY: Duration = Duration::from_millis(10_000);
const DEFAULT_MAX_SYN_RETRIES: u8 = 6;

impl Timer {
fn new() -> Timer {
Expand Down Expand Up @@ -295,6 +301,7 @@ impl Timer {
fn should_close(&self, timestamp: Instant) -> bool {
match *self {
Timer::Close { expires_at } if timestamp >= expires_at => true,
Timer::SynRetransmit { retries, .. } if retries >= DEFAULT_MAX_SYN_RETRIES => true,
_ => false,
}
}
Expand All @@ -307,6 +314,12 @@ impl Timer {
Timer::Idle {
keep_alive_at: None,
} => PollAt::Ingress,
Timer::SynRetransmit {
expires_at,
retries,
..
} if retries < DEFAULT_MAX_SYN_RETRIES => PollAt::Time(expires_at),
Timer::SynRetransmit { .. } => PollAt::Now,
Timer::Retransmit { expires_at, .. } => PollAt::Time(expires_at),
Timer::FastRetransmit => PollAt::Now,
Timer::Close { expires_at } => PollAt::Time(expires_at),
Expand Down Expand Up @@ -335,7 +348,7 @@ impl Timer {

fn set_for_retransmit(&mut self, timestamp: Instant, delay: Duration) {
match *self {
Timer::Idle { .. } | Timer::FastRetransmit { .. } => {
Timer::Idle { .. } | Timer::FastRetransmit { .. } | Timer::SynRetransmit { .. } => {
*self = Timer::Retransmit {
expires_at: timestamp + delay,
delay,
Expand All @@ -352,6 +365,26 @@ impl Timer {
}
}

fn set_for_syn_retransmit(&mut self, timestamp: Instant) {
match *self {
Timer::Idle { .. } => {
*self = Timer::SynRetransmit {
expires_at: timestamp + Duration::from_secs(1),
delay: Duration::from_secs(1),
retries: 1,
}
}
Timer::SynRetransmit { retries, .. } => {
*self = Timer::SynRetransmit {
expires_at: timestamp + Duration::from_secs(1 << retries),
delay: Duration::from_secs(1 << retries),
retries: retries + 1,
}
}
_ => (),
}
}

fn set_for_fast_retransmit(&mut self) {
*self = Timer::FastRetransmit
}
Expand Down Expand Up @@ -1980,7 +2013,7 @@ impl<'a> Socket<'a> {
let data_in_flight = self.remote_last_seq != self.local_seq_no;

// If we want to send a SYN and we haven't done so, do it!
if matches!(self.state, State::SynSent | State::SynReceived) && !data_in_flight {
if matches!(self.state, State::SynReceived) && !data_in_flight {
return true;
}

Expand Down Expand Up @@ -2099,7 +2132,12 @@ impl<'a> Socket<'a> {
}

// Decide whether we're sending a packet.
if self.seq_to_transmit(cx) {
if self.timer.should_close(cx.now()) {
// If we have spent enough time in the TIME-WAIT state, close the socket.
tcp_trace!("TIME-WAIT timer expired");
self.reset();
return Ok(());
} else if self.seq_to_transmit(cx) {
// If we have data to transmit and it fits into partner's window, do it.
tcp_trace!("outgoing segment will send data or flags");
} else if self.ack_to_transmit() && self.delayed_ack_expired(cx.now()) {
Expand All @@ -2114,11 +2152,6 @@ impl<'a> Socket<'a> {
} else if self.timer.should_keep_alive(cx.now()) {
// If we need to transmit a keep-alive packet, do it.
tcp_trace!("keep-alive timer expired");
} else if self.timer.should_close(cx.now()) {
// If we have spent enough time in the TIME-WAIT state, close the socket.
tcp_trace!("TIME-WAIT timer expired");
self.reset();
return Ok(());
} else {
return Ok(());
}
Expand Down Expand Up @@ -2169,6 +2202,13 @@ impl<'a> Socket<'a> {
// window len must NOT be scaled in SYNs.
repr.window_len = self.rx_buffer.window().min((1 << 16) - 1) as u16;
if self.state == State::SynSent {
// when the SynRetransmit timer don't time out, return immediately
match self.timer {
Timer::SynRetransmit { expires_at, .. } if cx.now() < expires_at => {
return Ok(());
}
_ => (),
}
repr.ack_number = None;
repr.window_scale = Some(self.remote_win_shift);
repr.sack_permitted = true;
Expand Down Expand Up @@ -2285,6 +2325,12 @@ impl<'a> Socket<'a> {
ip_repr.set_payload_len(repr.buffer_len());
emit(cx, (ip_repr, repr))?;

// while actually sending the syn packet, add or update the SynRetransmit timer
if let (State::SynSent, Timer::SynRetransmit { .. } | Timer::Idle { .. }) =
(self.state, self.timer)
{
self.timer.set_for_syn_retransmit(cx.now());
}
// We've sent something, whether useful data or a keep-alive packet, so rewind
// the keep-alive timer.
self.timer.rewind_keep_alive(cx.now(), self.keep_alive);
Expand Down
Loading