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 () && m_nextRxSeq > m_data.begin ()->first)
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 
200  if (headSeq > m_nextRxSeq)
201  {
202  // Generate a new SACK block
203  UpdateSackList (headSeq, tailSeq);
204  }
205 
206  NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
207  // Update variables
208  m_size += p->GetSize (); // Occupancy
209  for (i = m_data.begin (); i != m_data.end (); ++i)
210  {
211  if (i->first < m_nextRxSeq)
212  {
213  continue;
214  }
215  else if (i->first > m_nextRxSeq)
216  {
217  break;
218  };
219  m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
220  m_availBytes += i->second->GetSize ();
222  }
223  NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
224  if (m_gotFin && m_nextRxSeq == m_finSeq)
225  { // Account for the FIN packet
226  ++m_nextRxSeq;
227  };
228  return true;
229 }
230 
231 uint32_t
233 {
234  NS_LOG_FUNCTION (this);
235 
236  return m_sackList.size ();
237 }
238 
239 void
241 {
242  NS_LOG_FUNCTION (this << head << tail);
243  NS_ASSERT (head > m_nextRxSeq);
244 
245  TcpOptionSack::SackBlock current;
246  current.first = head;
247  current.second = tail;
248 
249  // The block "current" has been safely stored. Now we need to build the SACK
250  // list, to be advertised. From RFC 2018:
251  // (a) The first SACK block (i.e., the one immediately following the
252  // kind and length fields in the option) MUST specify the contiguous
253  // block of data containing the segment which triggered this ACK,
254  // unless that segment advanced the Acknowledgment Number field in
255  // the header. This assures that the ACK with the SACK option
256  // reflects the most recent change in the data receiver's buffer
257  // queue.
258  //
259  // (b) The data receiver SHOULD include as many distinct SACK blocks as
260  // possible in the SACK option. Note that the maximum available
261  // option space may not be sufficient to report all blocks present in
262  // the receiver's queue.
263  //
264  // (c) The SACK option SHOULD be filled out by repeating the most
265  // recently reported SACK blocks (based on first SACK blocks in
266  // previous SACK options) that are not subsets of a SACK block
267  // already included in the SACK option being constructed. This
268  // assures that in normal operation, any segment remaining part of a
269  // non-contiguous block of data held by the data receiver is reported
270  // in at least three successive SACK options, even for large-window
271  // TCP implementations [RFC1323]). After the first SACK block, the
272  // following SACK blocks in the SACK option may be listed in
273  // arbitrary order.
274 
275  m_sackList.push_front (current);
276 
277  // We have inserted the block at the beginning of the list. Now, we should
278  // check if any existing blocks overlap with that.
279  bool updated = false;
280  TcpOptionSack::SackList::iterator it = m_sackList.begin ();
281  TcpOptionSack::SackBlock begin = *it;
283  ++it;
284 
285  // Iterates until we examined all blocks in the list (maximum 4)
286  while (it != m_sackList.end ())
287  {
288  current = *it;
289 
290  // This is a left merge:
291  // [current_first; current_second] [beg_first; beg_second]
292  if (begin.first == current.second)
293  {
294  NS_ASSERT (current.first < begin.second);
295  merged = TcpOptionSack::SackBlock (current.first, begin.second);
296  updated = true;
297  }
298  // while this is a right merge
299  // [begin_first; begin_second] [current_first; current_second]
300  else if (begin.second == current.first)
301  {
302  NS_ASSERT (begin.first < current.second);
303  merged = TcpOptionSack::SackBlock (begin.first, current.second);
304  updated = true;
305  }
306 
307  // If we have merged the blocks (and the result is in merged) we should
308  // delete the current block (it), the first block, and insert the merged
309  // one at the beginning.
310  if (updated)
311  {
312  m_sackList.erase (it);
313  m_sackList.pop_front ();
314  m_sackList.push_front (merged);
315  it = m_sackList.begin ();
316  begin = *it;
317  updated = false;
318  }
319 
320  ++it;
321  }
322 
323  // Since the maximum blocks that fits into a TCP header are 4, there's no
324  // point on maintaining the others.
325  if (m_sackList.size () > 4)
326  {
327  m_sackList.pop_back ();
328  }
329 
330  // Please note that, if a block b is discarded and then a block contiguos
331  // to b is received, only that new block (without the b part) is reported.
332  // This is perfectly fine for the RFC point (a), given that we do not report any
333  // overlapping blocks shortly after.
334 }
335 
336 void
338 {
339  NS_LOG_FUNCTION (this << seq);
340 
341  TcpOptionSack::SackList::iterator it;
342  for (it = m_sackList.begin (); it != m_sackList.end (); )
343  {
344  TcpOptionSack::SackBlock block = *it;
345  NS_ASSERT (block.first < block.second);
346 
347  if (block.second <= seq)
348  {
349  it = m_sackList.erase (it);
350  }
351  else
352  {
353  it++;
354  }
355  }
356 }
357 
360 {
361  return m_sackList;
362 }
363 
365 TcpRxBuffer::Extract (uint32_t maxSize)
366 {
367  NS_LOG_FUNCTION (this << maxSize);
368 
369  uint32_t extractSize = std::min (maxSize, m_availBytes);
370  NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
371  if (extractSize == 0) return 0; // No contiguous block to return
372  NS_ASSERT (m_data.size ()); // At least we have something to extract
373  Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
374  BufIterator i;
375  while (extractSize)
376  { // Check the buffered data for delivery
377  i = m_data.begin ();
378  NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
379  // Check if we send the whole pkt or just a partial
380  uint32_t pktSize = i->second->GetSize ();
381  if (pktSize <= extractSize)
382  { // Whole packet is extracted
383  outPkt->AddAtEnd (i->second);
384  m_data.erase (i);
385  m_size -= pktSize;
386  m_availBytes -= pktSize;
387  extractSize -= pktSize;
388  }
389  else
390  { // Partial is extracted and done
391  outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
392  m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
393  m_data.erase (i);
394  m_size -= extractSize;
395  m_availBytes -= extractSize;
396  extractSize = 0;
397  }
398  }
399  if (outPkt->GetSize () == 0)
400  {
401  NS_LOG_LOGIC ("Nothing extracted.");
402  return 0;
403  }
404  NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_size
405  << ", num pkts in buffer=" << m_data.size ());
406  return outPkt;
407 }
408 
409 } //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:45
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:1790
std::list< SackBlock > SackList
SACK list definition.
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:796
void SetFinSequence(const SequenceNumber32 &s)
Set the FIN Sequence number (i.e., the one closing the connection)
void ClearSackList(const SequenceNumber32 &seq)
Remove old blocks from the sack list.
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:227
TcpOptionSack::SackList GetSackList() const
Get the sack list.
uint32_t GetSackListSize() const
Get the size of Sack list.
void IncNextRxSequence(void)
Increment the Next Sequence number.
bool m_gotFin
Did I received FIN packet?
void UpdateSackList(const SequenceNumber32 &head, const SequenceNumber32 &tail)
Update the sack list, with the block seq starting at the beginning.
Rx reordering buffer for TCP.
Definition: tcp-rx-buffer.h:73
void SetNextRxSequence(const SequenceNumber32 &s)
Set the Next Sequence number.
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)
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
std::pair< SequenceNumber32, SequenceNumber32 > SackBlock
SACK block definition.
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.
TcpOptionSack::SackList m_sackList
Sack list (updated constantly)
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:914
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