Bug 2133

Summary: In a TCP close procedure, assert fail when receiving pending data and in FIN_WAIT_2 state
Product: ns-3 Reporter: Matías Richart <matis18>
Component: tcpAssignee: natale.patriciello
Status: RESOLVED FIXED    
Severity: major CC: ljerezchaves, natale.patriciello, ns-bugs, tomh
Priority: P5    
Version: ns-3-dev   
Hardware: PC   
OS: Linux   
Attachments: Test case
Patch

Description Matías Richart 2015-06-02 15:36:13 UTC
When closing a TCP connection, it is possible for a node to receive data when it is in state FIN_WAIT_2. This is not considered in the code and when this happen the assert in function DoPeerClose() fails.
The problem is produced when both sides of the connection close simultaneously and there is pending data. This pending data arrives when the node is in state FIN_WAIT_2. What should happen is that the "hole" is completed and then wait in state TIME_WAIT for the socket to be closed.

I found the problem using DCE with a complicated mobile scenario. I attach an example where I reproduce the problem in a simpler scenario but using dce. Enabling logging for module TcpSocketBase helps following the state transitions and the problem.
I also attach a suggested patch.
Comment 1 Matías Richart 2015-06-02 15:37:56 UTC
Created attachment 2058 [details]
Test case
Comment 2 Matías Richart 2015-06-02 15:38:30 UTC
Created attachment 2059 [details]
Patch
Comment 3 Luciano Chaves 2015-10-06 20:31:37 UTC
I have also observed this same assert failure when the node is in the state FIN_WAIT_1.
Comment 4 natale.patriciello 2017-09-14 04:57:45 UTC
With the patch, a client which is not in ESTABLISHED state will never notify its close. Instead, simply modify the ASSERT in this way:

diff --git i/src/internet/model/tcp-socket-base.cc w/src/internet/model/tcp-socket-base.cc
index 1a5faa1bb..01f9be5d6 100644
--- i/src/internet/model/tcp-socket-base.cc
+++ w/src/internet/model/tcp-socket-base.cc
@@ -2233,7 +2233,11 @@ TcpSocketBase::PeerClose (Ptr<Packet> p, const TcpHeader& tcpHeader)
 void
 TcpSocketBase::DoPeerClose (void)
 {
-  NS_ASSERT (m_state == ESTABLISHED || m_state == SYN_RCVD);
+  // We can close the socket also when we are in FIN_WAIT state. It means
+  // we sent FIN, but then we have waited the other end to finish sending the
+  // data and its FIN until this moment.
+  NS_ASSERT (m_state == ESTABLISHED || m_state == SYN_RCVD || 
+      m_state == FIN_WAIT_1 || m_state == FIN_WAIT_2);
 
   // Move the state to CLOSE_WAIT
   NS_LOG_DEBUG (TcpStateName[m_state] << " -> CLOSE_WAIT")
Comment 5 Tom Henderson 2017-09-17 18:19:55 UTC
Natale's patch pushed in changeset 13071:5d6e40755113; please reopen if the solution is inadequate.