Skip to content

[inetstack] Bug Fix: Simultaneous close misses FIN resend #1538

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

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions network_simulator/input/tcp/close/close-local.pkt
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@

// Receive FIN segment.
+.1 TCP < F. seq 2001(0) ack 65537 win 65535 <nop>
// Send ACK on FIN segment.
+.0 TCP > . seq 65537(0) ack 2002 win 65534 <nop>


// Succeed to close connection immediately because we have linger set to 0.
+0 wait(500, ...) = 0

// Send ACK on FIN segment.
+.0 TCP > . seq 65537(0) ack 2002 win 65534 <nop>

19 changes: 11 additions & 8 deletions network_simulator/input/tcp/close/close-simultaneous.pkt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Tests for simultaneous close.
// Tests for simultaneous close. This is Figure 14 of RFC 793.

// Establish a connection.
+.0 socket(..., SOCK_STREAM, IPPROTO_TCP) = 500
Expand All @@ -18,14 +18,17 @@
// Close connection.
+.2 close(500) = 0

// Send FIN segment.
// Send FIN segment. Should move to FINWAIT-1
+.0 TCP > F. seq 65536(0) ack 101 win 65535 <nop>
// Receive ACK on FIN segment.
+.1 TCP < F. seq 101(0) ack 65537 win 65535 <nop>

// Succeed to close connection immediately because we have linger set to 0.
+0 wait(500, ...) = 0
// Receive FIN but no ack on FIN. Should move to Closing.
+.1 TCP < F. seq 101(0) ack 65536 win 65535 <nop>

// Resend FIN on simultaneous FIN segment with FIN ack.
+.0 TCP > F. seq 65536(0) ack 102 win 65534 <nop>

// Send ACK on FIN segment.
+.0 TCP > . seq 65537(0) ack 102 win 65534 <nop>
// Receive ACK on FIN segment. Should move to TIME WAIT
+.1 TCP < . seq 102(0) ack 65537 win 65534 <nop>

// Succeed to close connection immediately because we have linger set to 0.
+0 wait(500, ...) = 0
37 changes: 18 additions & 19 deletions src/rust/inetstack/protocols/layer4/tcp/established/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,12 @@ use crate::{
SharedDemiRuntime, SharedObject,
},
};
use ::futures::pin_mut;
use ::futures::FutureExt;
use ::futures::{join, pin_mut, FutureExt};
use ::std::{
net::SocketAddrV4,
ops::{Deref, DerefMut},
time::Duration,
time::Instant,
pin::pin,
time::{Duration, Instant},
};

//======================================================================================================================
Expand Down Expand Up @@ -206,19 +205,17 @@ impl SharedEstablishedSocket {
async fn local_close(&mut self) -> Result<(), Fail> {
// 1. Start close protocol by setting state and sending FIN.
self.cb.state = State::FinWait1;
Sender::push_fin_and_wait_for_ack(&mut self.cb).await?;

// 2. Got ACK to our FIN. Check if we also received a FIN from remote in the meantime.
let state: State = self.cb.state;
match state {
State::FinWait1 => {
self.cb.state = State::FinWait2;
// Haven't received a FIN yet from remote, so wait.
self.cb.receiver.wait_for_fin().await?;
},
State::Closing => self.cb.state = State::TimeWait,
state => unreachable!("Cannot be in any other state at this point: {:?}", state),
};
Sender::push_fin(&mut self.cb)?;

// 2. Wait for FIN and FIN ack.
let mut me2: SharedEstablishedSocket = self.clone();
let mut me3: SharedEstablishedSocket = self.clone();
let wait_for_fin = pin!(me3.cb.receiver.wait_for_fin().fuse());
let wait_for_fin_ack = pin!(Sender::wait_for_fin_ack(&mut me2.cb).fuse());
let (result1, result2) = join!(wait_for_fin, wait_for_fin_ack);
result1?;
result2?;

// 3. TIMED_WAIT
debug_assert_eq!(self.cb.state, State::TimeWait);
trace!("socket options: {:?}", self.cb.socket_options.get_linger());
Expand All @@ -232,8 +229,10 @@ impl SharedEstablishedSocket {
// 0. Move state forward
self.cb.state = State::LastAck;
// 1. Send FIN and wait for ack before closing.
Sender::push_fin_and_wait_for_ack(&mut self.cb).await?;
self.cb.state = State::Closed;
Sender::push_fin(&mut self.cb)?;
Sender::wait_for_fin_ack(&mut self.cb).await?;
debug_assert_eq!(self.cb.state, State::Closed);

Ok(())
}

Expand Down
Loading