Bug 2133 - In a TCP close procedure, assert fail when receiving pending data and in FIN_WAIT_2 state
In a TCP close procedure, assert fail when receiving pending data and in FIN_...
Status: RESOLVED FIXED
Product: ns-3
Classification: Unclassified
Component: tcp
ns-3-dev
PC Linux
: P5 major
Assigned To: natale.patriciello
:
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2015-06-02 15:36 EDT by Matías Richart
Modified: 2017-09-17 18:19 EDT (History)
4 users (show)

See Also:


Attachments
Test case (9.78 KB, patch)
2015-06-02 15:37 EDT, Matías Richart
Details | Diff
Patch (605 bytes, patch)
2015-06-02 15:38 EDT, Matías Richart
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Matías Richart 2015-06-02 15:36:13 EDT
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 EDT
Created attachment 2058 [details]
Test case
Comment 2 Matías Richart 2015-06-02 15:38:30 EDT
Created attachment 2059 [details]
Patch
Comment 3 Luciano Chaves 2015-10-06 20:31:37 EDT
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 EDT
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 EDT
Natale's patch pushed in changeset 13071:5d6e40755113; please reopen if the solution is inadequate.