Fix TcpSocketImpl rx buffer logic (closes 248)
authorRaj Bhattacharjea <raj.b@gatech.edu>
Tue, 29 Jul 2008 15:36:41 -0400
changeset 3493 53ec8893863d
parent 3492 7e1c5827504f
child 3496 5bb36e3c54d6
child 3499 a18520551cdf
Fix TcpSocketImpl rx buffer logic (closes 248)
src/internet-stack/tcp-socket-impl.cc
src/internet-stack/tcp-socket-impl.h
--- a/src/internet-stack/tcp-socket-impl.cc	Tue Jul 29 11:19:16 2008 -0700
+++ b/src/internet-stack/tcp-socket-impl.cc	Tue Jul 29 15:36:41 2008 -0400
@@ -1053,11 +1053,21 @@
   // 3) Received seq is > expected, just re-ack previous and buffer data
   if (tcpHeader.GetSequenceNumber () == m_nextRxSequence)
     { // If seq is expected seq
+      // Trim the end if necessary
       // 1) Update nextRxSeq
       // 2) Buffer this packet so Recv can read it
       // 3) Send the ack
+      UnAckData_t::iterator next = m_bufferedData.upper_bound (m_nextRxSequence);
+      if (next != m_bufferedData.end ())
+      {
+        SequenceNumber nextBufferedSeq = next->first;
+        if (m_nextRxSequence + SequenceNumber(s) > nextBufferedSeq)
+        {//tail end isn't all new, trim enough off the end
+          s = nextBufferedSeq - m_nextRxSequence;
+        }
+      }
+      p = p->CreateFragment (0,s);
       m_nextRxSequence += s;           // Advance next expected sequence
-      //bytesReceived += s;       // Statistics
       NS_LOG_LOGIC("Case 1, advanced nrxs to " << m_nextRxSequence );
       SocketAddressTag tag;
       tag.SetAddress (fromAddress);
@@ -1072,27 +1082,7 @@
       // Save for later delivery
       m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;  
       m_rxAvailable += p->GetSize ();
-      //putting this into the buffer might have filled in a sequence gap
-      //so we have to iterate through the list to find the largest contiguous
-      //sequenced chunk, and update m_rxAvailable appropriately
-      i = m_bufferedData.find (tcpHeader.GetSequenceNumber () );
-      UnAckData_t::iterator next = i;
-      next++;
-      while(next != m_bufferedData.end())
-        {
-          if(i->first + SequenceNumber(i->second->GetSize ()) == next->first)
-            {
-                //next packet is in sequence, count it
-                m_rxAvailable += next->second->GetSize();
-                m_nextRxSequence += next->second->GetSize();
-            }
-          else
-            {
-                break; //no more in this contiguous chunk
-            }
-          ++i;
-          ++next;
-        }
+      RxBufFinishInsert (tcpHeader.GetSequenceNumber ());
       NotifyDataRecv ();
       if (m_closeNotified)
         {
@@ -1107,20 +1097,93 @@
             }
         }
     }
-  else if (SequenceNumber (tcpHeader.GetSequenceNumber ()) >= m_nextRxSequence)
-    { // Need to buffer this one
+  else if (tcpHeader.GetSequenceNumber () > m_nextRxSequence)
+    { // Need to buffer this one, but trim off the front and back if necessary
       NS_LOG_LOGIC ("Case 2, buffering " << tcpHeader.GetSequenceNumber () );
+      UnAckData_t::iterator previous =
+          m_bufferedData.lower_bound (tcpHeader.GetSequenceNumber ());
+      SequenceNumber startSeq = tcpHeader.GetSequenceNumber();
+      if (previous != m_bufferedData.begin ())
+        {
+          --previous;
+          startSeq = previous->first + SequenceNumber(previous->second->GetSize());
+          if (startSeq > tcpHeader.GetSequenceNumber ())
+            {
+              s = tcpHeader.GetSequenceNumber () + SequenceNumber(s) - startSeq;
+            }
+          else
+            {
+              startSeq = tcpHeader.GetSequenceNumber();
+            }
+        }
+      //possibly trim off the end
+      UnAckData_t::iterator next = m_bufferedData.upper_bound (tcpHeader.GetSequenceNumber());
+      if (next != m_bufferedData.end ())
+      {
+        SequenceNumber nextBufferedSeq = next->first;
+        if (startSeq + SequenceNumber(s) > nextBufferedSeq)
+        {//tail end isn't all new either, trim enough off the end
+          s = nextBufferedSeq - startSeq;
+        }
+      }
+      p = p->CreateFragment (startSeq - tcpHeader.GetSequenceNumber (),s);
       UnAckData_t::iterator i = 
-        m_bufferedData.find (tcpHeader.GetSequenceNumber () );
+          m_bufferedData.find (startSeq);
       if (i != m_bufferedData.end () )
         {
-          i->second = 0; // relase reference to already buffered
+          if(p->GetSize() > i->second->GetSize())
+          {
+            i->second = 0; // relase reference to already buffered
+          }
+          else
+          {
+            p = i->second;
+          }
         }
       // Save for later delivery
       SocketAddressTag tag;
       tag.SetAddress (fromAddress);
       p->AddTag (tag);
-      m_bufferedData[tcpHeader.GetSequenceNumber () ] = p;  
+      m_bufferedData[startSeq] = p;  
+      i = m_bufferedData.find (startSeq);
+      next = i;
+      ++next;
+      if(next != m_bufferedData.end())
+        {
+          NS_ASSERT(next->first >= i->first + SequenceNumber(i->second->GetSize ()));
+        }
+    }
+  else if (tcpHeader.GetSequenceNumber () + SequenceNumber(s) > m_nextRxSequence)
+    {//parial new data case, only part of the packet is new data
+      //trim the beginning
+      s = tcpHeader.GetSequenceNumber () + SequenceNumber(s) - m_nextRxSequence; //how much new
+      //possibly trim off the end
+      UnAckData_t::iterator next = m_bufferedData.upper_bound (m_nextRxSequence);
+      if (next != m_bufferedData.end ())
+      {
+        SequenceNumber nextBufferedSeq = next->first;
+        if (m_nextRxSequence + SequenceNumber(s) > nextBufferedSeq)
+        {//tail end isn't all new either, trim enough off the end
+          s = nextBufferedSeq - m_nextRxSequence;
+        }
+      }
+      p = p->CreateFragment (m_nextRxSequence - tcpHeader.GetSequenceNumber (),s);
+      SequenceNumber start = m_nextRxSequence;
+      m_nextRxSequence += s;           // Advance next expected sequence
+      SocketAddressTag tag;
+      tag.SetAddress (fromAddress);
+      p->AddTag (tag);
+      //buffer the new fragment, it'll be read by call to Recv
+      UnAckData_t::iterator i = m_bufferedData.find (start);
+      if (i != m_bufferedData.end () ) //we found it already in the buffer
+        {
+          i->second = 0; // relase reference to already buffered
+        }
+      // Save for later delivery
+      m_bufferedData[start] = p;
+      m_rxAvailable += p->GetSize ();
+      RxBufFinishInsert(start);
+      NotifyDataRecv ();
     }
   else
     { // debug
@@ -1142,6 +1205,36 @@
   }
 }
 
+void TcpSocketImpl::RxBufFinishInsert (SequenceNumber seq)
+{
+  //putting data into the buffer might have filled in a sequence gap so we have
+  //to iterate through the list to find the largest contiguous sequenced chunk,
+  //and update m_rxAvailable and m_nextRxSequence appropriately
+  UnAckData_t::iterator i = m_bufferedData.find (seq);
+  UnAckData_t::iterator next = i;
+  ++next;
+  //make sure the buffer is logically sequenced
+  if(next != m_bufferedData.end())
+  {
+    NS_ASSERT(next->first >= i->first + SequenceNumber(i->second->GetSize ()));
+  }
+  while(next != m_bufferedData.end())
+  {
+    if(i->first + SequenceNumber(i->second->GetSize ()) == next->first)
+    {
+      //next packet is in sequence, count it
+      m_rxAvailable += next->second->GetSize();
+      m_nextRxSequence += next->second->GetSize();
+    }
+    else
+    {
+      break; //no more in this contiguous chunk
+    }
+    ++i;
+    ++next;
+  }
+}
+
 void TcpSocketImpl::DelAckTimeout ()
 {
   m_delAckCount = 0;
--- a/src/internet-stack/tcp-socket-impl.h	Tue Jul 29 11:19:16 2008 -0700
+++ b/src/internet-stack/tcp-socket-impl.h	Tue Jul 29 15:36:41 2008 -0400
@@ -123,6 +123,7 @@
 
   // Manage data tx/rx
   void NewRx (Ptr<Packet>, const TcpHeader&, const Address&);
+  void RxBufFinishInsert (SequenceNumber);
   // XXX This should be virtual and overridden
   Ptr<TcpSocketImpl> Copy ();
   void NewAck (SequenceNumber seq);