A Discrete-Event Network Simulator
API
tcp-rx-buffer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010 Adrian Sai-wah Tam
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Author: Adrian Sai-wah Tam <adrian.sw.tam@gmail.com>
18  */
19 
20 #include "tcp-rx-buffer.h"
21 
22 #include "ns3/log.h"
23 #include "ns3/packet.h"
24 
25 namespace ns3
26 {
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  return tid;
44 }
45 
46 /* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
47  * there are attributes SndBufSize and RcvBufSize to control the default Tx and
48  * Rx window sizes respectively, with default of 128 KiByte. The attribute
49  * RcvBufSize is passed to TcpRxBuffer by TcpSocketBase::SetRcvBufSize() and in
50  * turn, TcpRxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
51  * initialized below is insignificant.
52  */
54  : m_nextRxSeq(n),
55  m_gotFin(false),
56  m_size(0),
57  m_maxBuffer(32768),
58  m_availBytes(0)
59 {
60 }
61 
63 {
64 }
65 
68 {
69  return m_nextRxSeq;
70 }
71 
72 void
74 {
75  m_nextRxSeq = s;
76 }
77 
78 uint32_t
80 {
81  return m_maxBuffer;
82 }
83 
84 void
86 {
87  m_maxBuffer = s;
88 }
89 
90 uint32_t
92 {
93  return m_size;
94 }
95 
96 uint32_t
98 {
99  return m_availBytes;
100 }
101 
102 void
104 {
105  NS_LOG_FUNCTION(this);
106  // Increment nextRxSeq is valid only if we don't have any data buffered,
107  // this is supposed to be called only during the three-way handshake
108  NS_ASSERT(m_size == 0);
109  m_nextRxSeq++;
110 }
111 
112 // Return the lowest sequence number that this TcpRxBuffer cannot accept
115 {
116  if (m_gotFin)
117  { // No data allowed beyond FIN
118  return m_finSeq;
119  }
120  else if (!m_data.empty() && m_nextRxSeq > m_data.begin()->first)
121  { // No data allowed beyond Rx window allowed
122  return m_data.begin()->first + SequenceNumber32(m_maxBuffer);
123  }
125 }
126 
127 void
129 {
130  NS_LOG_FUNCTION(this);
131 
132  m_gotFin = true;
133  m_finSeq = s;
134  if (m_nextRxSeq == m_finSeq)
135  {
136  ++m_nextRxSeq;
137  }
138 }
139 
140 bool
142 {
143  return (m_gotFin && m_finSeq < m_nextRxSeq);
144 }
145 
146 bool
148 {
149  NS_LOG_FUNCTION(this << p << tcph);
150 
151  uint32_t pktSize = p->GetSize();
152  SequenceNumber32 headSeq = tcph.GetSequenceNumber();
153  SequenceNumber32 tailSeq = headSeq + SequenceNumber32(pktSize);
154  NS_LOG_LOGIC("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
155  << ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
156 
157  // Trim packet to fit Rx window specification
158  if (headSeq < m_nextRxSeq)
159  {
160  headSeq = m_nextRxSeq;
161  }
162  if (!m_data.empty())
163  {
164  SequenceNumber32 maxSeq = m_data.begin()->first + SequenceNumber32(m_maxBuffer);
165  if (maxSeq < tailSeq)
166  {
167  tailSeq = maxSeq;
168  }
169  if (tailSeq < headSeq)
170  {
171  headSeq = tailSeq;
172  }
173  }
174  // Remove overlapped bytes from packet
175  auto i = m_data.begin();
176  while (i != m_data.end() && i->first <= tailSeq)
177  {
178  SequenceNumber32 lastByteSeq = i->first + SequenceNumber32(i->second->GetSize());
179  if (lastByteSeq > headSeq)
180  {
181  if (i->first > headSeq && lastByteSeq < tailSeq)
182  { // Rare case: Existing packet is embedded fully in the new packet
183  m_size -= i->second->GetSize();
184  m_data.erase(i++);
185  continue;
186  }
187  if (i->first <= headSeq)
188  { // Incoming head is overlapped
189  headSeq = lastByteSeq;
190  }
191  if (lastByteSeq >= tailSeq)
192  { // Incoming tail is overlapped
193  tailSeq = i->first;
194  }
195  }
196  ++i;
197  }
198  // We now know how much we are going to store, trim the packet
199  if (headSeq >= tailSeq)
200  {
201  NS_LOG_LOGIC("Nothing to buffer");
202  return false; // Nothing to buffer anyway
203  }
204  else
205  {
206  uint32_t start = static_cast<uint32_t>(headSeq - tcph.GetSequenceNumber());
207  auto length = static_cast<uint32_t>(tailSeq - headSeq);
208  p = p->CreateFragment(start, length);
209  NS_ASSERT(length == p->GetSize());
210  }
211  // Insert packet into buffer
212  NS_ASSERT(m_data.find(headSeq) == m_data.end()); // Shouldn't be there yet
213  m_data[headSeq] = p;
214 
215  if (headSeq > m_nextRxSeq)
216  {
217  // Generate a new SACK block
218  UpdateSackList(headSeq, tailSeq);
219  }
220 
221  NS_LOG_LOGIC("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize());
222  // Update variables
223  m_size += p->GetSize(); // Occupancy
224  for (i = m_data.begin(); i != m_data.end(); ++i)
225  {
226  if (i->first < m_nextRxSeq)
227  {
228  continue;
229  }
230  else if (i->first > m_nextRxSeq)
231  {
232  break;
233  };
234  m_nextRxSeq = i->first + SequenceNumber32(i->second->GetSize());
235  m_availBytes += i->second->GetSize();
237  }
238  NS_LOG_LOGIC("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
239  if (m_gotFin && m_nextRxSeq == m_finSeq)
240  { // Account for the FIN packet
241  ++m_nextRxSeq;
242  };
243  return true;
244 }
245 
246 uint32_t
248 {
249  NS_LOG_FUNCTION(this);
250 
251  return static_cast<uint32_t>(m_sackList.size());
252 }
253 
254 void
256 {
257  NS_LOG_FUNCTION(this << head << tail);
258  NS_ASSERT(head > m_nextRxSeq);
259 
260  TcpOptionSack::SackBlock current;
261  current.first = head;
262  current.second = tail;
263 
264  // The block "current" has been safely stored. Now we need to build the SACK
265  // list, to be advertised. From RFC 2018:
266  // (a) The first SACK block (i.e., the one immediately following the
267  // kind and length fields in the option) MUST specify the contiguous
268  // block of data containing the segment which triggered this ACK,
269  // unless that segment advanced the Acknowledgment Number field in
270  // the header. This assures that the ACK with the SACK option
271  // reflects the most recent change in the data receiver's buffer
272  // queue.
273  //
274  // (b) The data receiver SHOULD include as many distinct SACK blocks as
275  // possible in the SACK option. Note that the maximum available
276  // option space may not be sufficient to report all blocks present in
277  // the receiver's queue.
278  //
279  // (c) The SACK option SHOULD be filled out by repeating the most
280  // recently reported SACK blocks (based on first SACK blocks in
281  // previous SACK options) that are not subsets of a SACK block
282  // already included in the SACK option being constructed. This
283  // assures that in normal operation, any segment remaining part of a
284  // non-contiguous block of data held by the data receiver is reported
285  // in at least three successive SACK options, even for large-window
286  // TCP implementations [RFC1323]). After the first SACK block, the
287  // following SACK blocks in the SACK option may be listed in
288  // arbitrary order.
289 
290  m_sackList.push_front(current);
291 
292  // We have inserted the block at the beginning of the list. Now, we should
293  // check if any existing blocks overlap with that.
294  bool updated = false;
295  auto it = m_sackList.begin();
296  TcpOptionSack::SackBlock begin = *it;
298  ++it;
299 
300  // Iterates until we examined all blocks in the list (maximum 4)
301  while (it != m_sackList.end())
302  {
303  current = *it;
304 
305  // This is a left merge:
306  // [current_first; current_second] [beg_first; beg_second]
307  if (begin.first == current.second)
308  {
309  NS_ASSERT(current.first < begin.second);
310  merged = TcpOptionSack::SackBlock(current.first, begin.second);
311  updated = true;
312  }
313  // while this is a right merge
314  // [begin_first; begin_second] [current_first; current_second]
315  else if (begin.second == current.first)
316  {
317  NS_ASSERT(begin.first < current.second);
318  merged = TcpOptionSack::SackBlock(begin.first, current.second);
319  updated = true;
320  }
321 
322  // If we have merged the blocks (and the result is in merged) we should
323  // delete the current block (it), the first block, and insert the merged
324  // one at the beginning.
325  if (updated)
326  {
327  m_sackList.erase(it);
328  m_sackList.pop_front();
329  m_sackList.push_front(merged);
330  it = m_sackList.begin();
331  begin = *it;
332  updated = false;
333  }
334 
335  ++it;
336  }
337 
338  // Since the maximum blocks that fits into a TCP header are 4, there's no
339  // point on maintaining the others.
340  if (m_sackList.size() > 4)
341  {
342  m_sackList.pop_back();
343  }
344 
345  // Please note that, if a block b is discarded and then a block contiguous
346  // to b is received, only that new block (without the b part) is reported.
347  // This is perfectly fine for the RFC point (a), given that we do not report any
348  // overlapping blocks shortly after.
349 }
350 
351 void
353 {
354  NS_LOG_FUNCTION(this << seq);
355 
356  for (auto it = m_sackList.begin(); it != m_sackList.end();)
357  {
358  TcpOptionSack::SackBlock block = *it;
359  NS_ASSERT(block.first < block.second);
360 
361  if (block.second <= seq)
362  {
363  it = m_sackList.erase(it);
364  }
365  else
366  {
367  it++;
368  }
369  }
370 }
371 
374 {
375  return m_sackList;
376 }
377 
379 TcpRxBuffer::Extract(uint32_t maxSize)
380 {
381  NS_LOG_FUNCTION(this << maxSize);
382 
383  uint32_t extractSize = std::min(maxSize, m_availBytes);
384  NS_LOG_LOGIC("Requested to extract " << extractSize
385  << " bytes from TcpRxBuffer of size=" << m_size);
386  if (extractSize == 0)
387  {
388  return nullptr; // No contiguous block to return
389  }
390  NS_ASSERT(!m_data.empty()); // At least we have something to extract
391  Ptr<Packet> outPkt = Create<Packet>(); // The packet that contains all the data to return
392  BufIterator i;
393  while (extractSize)
394  { // Check the buffered data for delivery
395  i = m_data.begin();
396  NS_ASSERT(i->first <= m_nextRxSeq); // in-sequence data expected
397  // Check if we send the whole pkt or just a partial
398  uint32_t pktSize = i->second->GetSize();
399  if (pktSize <= extractSize)
400  { // Whole packet is extracted
401  outPkt->AddAtEnd(i->second);
402  m_data.erase(i);
403  m_size -= pktSize;
405  extractSize -= pktSize;
406  }
407  else
408  { // Partial is extracted and done
409  outPkt->AddAtEnd(i->second->CreateFragment(0, extractSize));
410  m_data[i->first + SequenceNumber32(extractSize)] =
411  i->second->CreateFragment(extractSize, pktSize - extractSize);
412  m_data.erase(i);
413  m_size -= extractSize;
414  m_availBytes -= extractSize;
415  extractSize = 0;
416  }
417  }
418  if (outPkt->GetSize() == 0)
419  {
420  NS_LOG_LOGIC("Nothing extracted.");
421  return nullptr;
422  }
423  NS_LOG_LOGIC("Extracted " << outPkt->GetSize() << " bytes, bufsize=" << m_size
424  << ", num pkts in buffer=" << m_data.size());
425  return outPkt;
426 }
427 
428 } // namespace ns3
#define min(a, b)
Definition: 80211b.c:41
A base class which provides memory management and object aggregation.
Definition: object.h:89
void AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:354
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:861
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:238
Header for the Transmission Control Protocol.
Definition: tcp-header.h:47
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:118
std::list< SackBlock > SackList
SACK list definition.
std::pair< SequenceNumber32, SequenceNumber32 > SackBlock
SACK block definition.
Rx reordering buffer for TCP.
Definition: tcp-rx-buffer.h:76
~TcpRxBuffer() override
uint32_t GetSackListSize() const
Get the size of Sack list.
Ptr< Packet > Extract(uint32_t maxSize)
Extract data from the head of the buffer as indicated by nextRxSeq.
bool Finished()
Check if the buffer did receive all the data (and the connection is closed)
static TypeId GetTypeId()
Get the type ID.
void SetFinSequence(const SequenceNumber32 &s)
Set the FIN Sequence number (i.e., the one closing the connection)
void SetMaxBufferSize(uint32_t s)
Set the Maximum buffer size.
SequenceNumber32 NextRxSequence() const
Get Next Rx Sequence number.
std::map< SequenceNumber32, Ptr< Packet > > m_data
Corresponding data (may be null)
void SetNextRxSequence(const SequenceNumber32 &s)
Set the Next Sequence number.
std::map< SequenceNumber32, Ptr< Packet > >::iterator BufIterator
container for data stored in the buffer
SequenceNumber32 m_finSeq
Seqnum of the FIN packet.
uint32_t m_availBytes
Number of bytes available to read, i.e.
void IncNextRxSequence()
Increment the Next Sequence number.
uint32_t MaxBufferSize() const
Get the Maximum buffer size.
uint32_t Size() const
Get the actual buffer occupancy.
bool Add(Ptr< Packet > p, const TcpHeader &tcph)
Insert a packet into the buffer and update the availBytes counter to reflect the number of bytes read...
uint32_t m_maxBuffer
Upper bound of the number of data bytes in buffer (RCV.WND)
SequenceNumber32 MaxRxSequence() const
Get the lowest sequence number that this TcpRxBuffer cannot accept.
TracedValue< SequenceNumber32 > m_nextRxSeq
Seqnum of the first missing byte in data (RCV.NXT)
TcpRxBuffer(uint32_t n=0)
Constructor.
void UpdateSackList(const SequenceNumber32 &head, const SequenceNumber32 &tail)
Update the sack list, with the block seq starting at the beginning.
uint32_t Available() const
Get the actual number of bytes available to be read.
TcpOptionSack::SackList GetSackList() const
Get the sack list.
uint32_t m_size
Number of total data bytes in the buffer, not necessarily contiguous.
void ClearSackList(const SequenceNumber32 &seq)
Remove old blocks from the sack list.
bool m_gotFin
Did I received FIN packet?
TcpOptionSack::SackList m_sackList
Sack list (updated constantly)
a unique identifier for an interface.
Definition: type-id.h:59
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
uint32_t pktSize
packet size used for the simulation (in bytes)