A Discrete-Event Network Simulator
API
tcp-rx-buffer.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2010 Adrian Sai-wah Tam
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
19  */
20 
21 #include "ns3/packet.h"
22 #include "ns3/fatal-error.h"
23 #include "ns3/log.h"
24 #include "tcp-rx-buffer.h"
25 
26 namespace ns3 {
27 
28 NS_LOG_COMPONENT_DEFINE ("TcpRxBuffer");
29 
30 NS_OBJECT_ENSURE_REGISTERED (TcpRxBuffer);
31 
32 TypeId
34 {
35  static TypeId tid = TypeId ("ns3::TcpRxBuffer")
36  .SetParent<Object> ()
37  .SetGroupName ("Internet")
38  .AddConstructor<TcpRxBuffer> ()
39  .AddTraceSource ("NextRxSequence",
40  "Next sequence number expected (RCV.NXT)",
42  "ns3::SequenceNumber32TracedValueCallback")
43  ;
44  return tid;
45 }
46 
47 /* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
48  * there are attributes SndBufSize and RcvBufSize to control the default Tx and
49  * Rx window sizes respectively, with default of 128 KiByte. The attribute
50  * RcvBufSize is passed to TcpRxBuffer by TcpSocketBase::SetRcvBufSize() and in
51  * turn, TcpRxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
52  * initialized below is insignificant.
53  */
55  : m_nextRxSeq (n), m_gotFin (false), m_size (0), m_maxBuffer (32768), m_availBytes (0)
56 {
57 }
58 
60 {
61 }
62 
65 {
66  return m_nextRxSeq;
67 }
68 
69 void
71 {
72  m_nextRxSeq = s;
73 }
74 
75 uint32_t
77 {
78  return m_maxBuffer;
79 }
80 
81 void
83 {
84  m_maxBuffer = s;
85 }
86 
87 uint32_t
88 TcpRxBuffer::Size (void) const
89 {
90  return m_size;
91 }
92 
93 uint32_t
95 {
96  return m_availBytes;
97 }
98 
99 void
101 {
102  NS_LOG_FUNCTION (this);
103  // Increment nextRxSeq is valid only if we don't have any data buffered,
104  // this is supposed to be called only during the three-way handshake
105  NS_ASSERT (m_size == 0);
106  m_nextRxSeq++;
107 }
108 
109 // Return the lowest sequence number that this TcpRxBuffer cannot accept
112 {
113  if (m_gotFin)
114  { // No data allowed beyond FIN
115  return m_finSeq;
116  }
117  else if (m_data.size ())
118  { // No data allowed beyond Rx window allowed
119  return m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
120  }
122 }
123 
124 void
126 {
127  NS_LOG_FUNCTION (this);
128 
129  m_gotFin = true;
130  m_finSeq = s;
131  if (m_nextRxSeq == m_finSeq) ++m_nextRxSeq;
132 }
133 
134 bool
136 {
137  return (m_gotFin && m_finSeq < m_nextRxSeq);
138 }
139 
140 bool
142 {
143  NS_LOG_FUNCTION (this << p << tcph);
144 
145  uint32_t pktSize = p->GetSize ();
146  SequenceNumber32 headSeq = tcph.GetSequenceNumber ();
147  SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize);
148  NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
149  << ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
150 
151  // Trim packet to fit Rx window specification
152  if (headSeq < m_nextRxSeq) headSeq = m_nextRxSeq;
153  if (m_data.size ())
154  {
155  SequenceNumber32 maxSeq = m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
156  if (maxSeq < tailSeq) tailSeq = maxSeq;
157  if (tailSeq < headSeq) headSeq = tailSeq;
158  }
159  // Remove overlapped bytes from packet
160  BufIterator i = m_data.begin ();
161  while (i != m_data.end () && i->first <= tailSeq)
162  {
163  SequenceNumber32 lastByteSeq = i->first + SequenceNumber32 (i->second->GetSize ());
164  if (lastByteSeq > headSeq)
165  {
166  if (i->first > headSeq && lastByteSeq < tailSeq)
167  { // Rare case: Existing packet is embedded fully in the new packet
168  m_size -= i->second->GetSize ();
169  m_data.erase (i++);
170  continue;
171  }
172  if (i->first <= headSeq)
173  { // Incoming head is overlapped
174  headSeq = lastByteSeq;
175  }
176  if (lastByteSeq >= tailSeq)
177  { // Incoming tail is overlapped
178  tailSeq = i->first;
179  }
180  }
181  ++i;
182  }
183  // We now know how much we are going to store, trim the packet
184  if (headSeq >= tailSeq)
185  {
186  NS_LOG_LOGIC ("Nothing to buffer");
187  return false; // Nothing to buffer anyway
188  }
189  else
190  {
191  uint32_t start = headSeq - tcph.GetSequenceNumber ();
192  uint32_t length = tailSeq - headSeq;
193  p = p->CreateFragment (start, length);
194  NS_ASSERT (length == p->GetSize ());
195  }
196  // Insert packet into buffer
197  NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet
198  m_data [ headSeq ] = p;
199  NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
200  // Update variables
201  m_size += p->GetSize (); // Occupancy
202  for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
203  {
204  if (i->first < m_nextRxSeq)
205  {
206  continue;
207  }
208  else if (i->first > m_nextRxSeq)
209  {
210  break;
211  };
212  m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
213  m_availBytes += i->second->GetSize ();
214  }
215  NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
216  if (m_gotFin && m_nextRxSeq == m_finSeq)
217  { // Account for the FIN packet
218  ++m_nextRxSeq;
219  };
220  return true;
221 }
222 
224 TcpRxBuffer::Extract (uint32_t maxSize)
225 {
226  NS_LOG_FUNCTION (this << maxSize);
227 
228  uint32_t extractSize = std::min (maxSize, m_availBytes);
229  NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
230  if (extractSize == 0) return 0; // No contiguous block to return
231  NS_ASSERT (m_data.size ()); // At least we have something to extract
232  Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
233  BufIterator i;
234  while (extractSize)
235  { // Check the buffered data for delivery
236  i = m_data.begin ();
237  NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
238  // Check if we send the whole pkt or just a partial
239  uint32_t pktSize = i->second->GetSize ();
240  if (pktSize <= extractSize)
241  { // Whole packet is extracted
242  outPkt->AddAtEnd (i->second);
243  m_data.erase (i);
244  m_size -= pktSize;
245  m_availBytes -= pktSize;
246  extractSize -= pktSize;
247  }
248  else
249  { // Partial is extracted and done
250  outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
251  m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
252  m_data.erase (i);
253  m_size -= extractSize;
254  m_availBytes -= extractSize;
255  extractSize = 0;
256  }
257  }
258  if (outPkt->GetSize () == 0)
259  {
260  NS_LOG_LOGIC ("Nothing extracted.");
261  return 0;
262  }
263  NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_size
264  << ", num pkts in buffer=" << m_data.size ());
265  return outPkt;
266 }
267 
268 } //namepsace ns3
uint32_t m_availBytes
Number of bytes available to read, i.e.
uint32_t m_maxBuffer
Upper bound of the number of data bytes in buffer (RCV.WND)
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:143
bool Add(Ptr< Packet > p, TcpHeader const &tcph)
Insert a packet into the buffer and update the availBytes counter to reflect the number of bytes read...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
TracedValue< SequenceNumber32 > m_nextRxSeq
Seqnum of the first missing byte in data (RCV.NXT)
#define min(a, b)
Definition: 80211b.c:44
def start()
Definition: core.py:1482
uint32_t Available() const
Get the actual number of bytes available to be read.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file...
Definition: assert.h:67
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
uint32_t GetSize(void) const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:792
void SetFinSequence(const SequenceNumber32 &s)
Set the FIN Sequence number (i.e., the one closing the connection)
SequenceNumber32 NextRxSequence(void) const
Get Next Rx Sequence number.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
SequenceNumber32 MaxRxSequence(void) const
Get the lowest sequence number that this TcpRxBuffer cannot accept.
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Create a new packet which contains a fragment of the original packet.
Definition: packet.cc:228
void IncNextRxSequence(void)
Increment the Next Sequence number.
bool m_gotFin
Did I received FIN packet?
class for the reordering buffer that keeps the data from lower layer, i.e.
Definition: tcp-rx-buffer.h:40
void SetNextRxSequence(const SequenceNumber32 &s)
Set the Next Sequence number.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
void SetMaxBufferSize(uint32_t s)
Set the Maximum buffer size.
TcpRxBuffer(uint32_t n=0)
Constructor.
SequenceNumber32 m_finSeq
Seqnum of the FIN packet.
Ptr< Packet > Extract(uint32_t maxSize)
Extract data from the head of the buffer as indicated by nextRxSeq.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:44
std::map< SequenceNumber32, Ptr< Packet > > m_data
Corresponding data (may be null)
uint32_t MaxBufferSize(void) const
Get the Maximum buffer size.
uint32_t m_size
Number of total data bytes in the buffer, not necessarily contiguous.
static TypeId GetTypeId(void)
Get the type ID.
A base class which provides memory management and object aggregation.
Definition: object.h:87
uint32_t Size(void) const
Get the actual buffer occupancy.
a unique identifier for an interface.
Definition: type-id.h:58
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:904
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
virtual ~TcpRxBuffer()
bool Finished(void)
Check if the buffer did receive all the data (and the connection is closed)
std::map< SequenceNumber32, Ptr< Packet > >::iterator BufIterator
container for data stored in the buffer