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  .AddConstructor<TcpRxBuffer> ()
38  .AddTraceSource ("NextRxSequence",
39  "Next sequence number expected (RCV.NXT)",
41  "ns3::SequenceNumber32TracedValueCallback")
42  ;
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), m_gotFin (false), m_size (0), m_maxBuffer (32768), m_availBytes (0)
55 {
56 }
57 
59 {
60 }
61 
64 {
65  return m_nextRxSeq;
66 }
67 
68 void
70 {
71  m_nextRxSeq = s;
72 }
73 
74 uint32_t
76 {
77  return m_maxBuffer;
78 }
79 
80 void
82 {
83  m_maxBuffer = s;
84 }
85 
86 uint32_t
87 TcpRxBuffer::Size (void) const
88 {
89  return m_size;
90 }
91 
92 uint32_t
94 {
95  return m_availBytes;
96 }
97 
98 void
100 {
101  NS_LOG_FUNCTION (this);
102  // Increment nextRxSeq is valid only if we don't have any data buffered,
103  // this is supposed to be called only during the three-way handshake
104  NS_ASSERT (m_size == 0);
105  m_nextRxSeq++;
106 }
107 
108 // Return the lowest sequence number that this TcpRxBuffer cannot accept
111 {
112  if (m_gotFin)
113  { // No data allowed beyond FIN
114  return m_finSeq;
115  }
116  else if (m_data.size ())
117  { // No data allowed beyond Rx window allowed
118  return m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
119  }
121 }
122 
123 void
125 {
126  NS_LOG_FUNCTION (this);
127 
128  m_gotFin = true;
129  m_finSeq = s;
130  if (m_nextRxSeq == m_finSeq) ++m_nextRxSeq;
131 }
132 
133 bool
135 {
136  return (m_gotFin && m_finSeq < m_nextRxSeq);
137 }
138 
139 bool
141 {
142  NS_LOG_FUNCTION (this << p << tcph);
143 
144  uint32_t pktSize = p->GetSize ();
145  SequenceNumber32 headSeq = tcph.GetSequenceNumber ();
146  SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize);
147  NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
148  << ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
149 
150  // Trim packet to fit Rx window specification
151  if (headSeq < m_nextRxSeq) headSeq = m_nextRxSeq;
152  if (m_data.size ())
153  {
154  SequenceNumber32 maxSeq = m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
155  if (maxSeq < tailSeq) tailSeq = maxSeq;
156  if (tailSeq < headSeq) headSeq = tailSeq;
157  }
158  // Remove overlapped bytes from packet
159  BufIterator i = m_data.begin ();
160  while (i != m_data.end () && i->first <= tailSeq)
161  {
162  SequenceNumber32 lastByteSeq = i->first + SequenceNumber32 (i->second->GetSize ());
163  if (lastByteSeq > headSeq)
164  {
165  if (i->first > headSeq && lastByteSeq < tailSeq)
166  { // Rare case: Existing packet is embedded fully in the new packet
167  m_size -= i->second->GetSize ();
168  m_data.erase (i++);
169  continue;
170  }
171  if (i->first <= headSeq)
172  { // Incoming head is overlapped
173  headSeq = lastByteSeq;
174  }
175  if (lastByteSeq >= tailSeq)
176  { // Incoming tail is overlapped
177  tailSeq = i->first;
178  }
179  }
180  ++i;
181  }
182  // We now know how much we are going to store, trim the packet
183  if (headSeq >= tailSeq)
184  {
185  NS_LOG_LOGIC ("Nothing to buffer");
186  return false; // Nothing to buffer anyway
187  }
188  else
189  {
190  uint32_t start = headSeq - tcph.GetSequenceNumber ();
191  uint32_t length = tailSeq - headSeq;
192  p = p->CreateFragment (start, length);
193  NS_ASSERT (length == p->GetSize ());
194  }
195  // Insert packet into buffer
196  NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet
197  m_data [ headSeq ] = p;
198  NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
199  // Update variables
200  m_size += p->GetSize (); // Occupancy
201  for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
202  {
203  if (i->first < m_nextRxSeq)
204  {
205  continue;
206  }
207  else if (i->first > m_nextRxSeq)
208  {
209  break;
210  };
211  m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
212  m_availBytes += i->second->GetSize ();
213  }
214  NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
215  if (m_gotFin && m_nextRxSeq == m_finSeq)
216  { // Account for the FIN packet
217  ++m_nextRxSeq;
218  };
219  return true;
220 }
221 
223 TcpRxBuffer::Extract (uint32_t maxSize)
224 {
225  NS_LOG_FUNCTION (this << maxSize);
226 
227  uint32_t extractSize = std::min (maxSize, m_availBytes);
228  NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
229  if (extractSize == 0) return 0; // No contiguous block to return
230  NS_ASSERT (m_data.size ()); // At least we have something to extract
231  Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
232  BufIterator i;
233  while (extractSize)
234  { // Check the buffered data for delivery
235  i = m_data.begin ();
236  NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
237  // Check if we send the whole pkt or just a partial
238  uint32_t pktSize = i->second->GetSize ();
239  if (pktSize <= extractSize)
240  { // Whole packet is extracted
241  outPkt->AddAtEnd (i->second);
242  m_data.erase (i);
243  m_size -= pktSize;
244  m_availBytes -= pktSize;
245  extractSize -= pktSize;
246  }
247  else
248  { // Partial is extracted and done
249  outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
250  m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
251  m_data.erase (i);
252  m_size -= extractSize;
253  m_availBytes -= extractSize;
254  extractSize = 0;
255  }
256  }
257  if (outPkt->GetSize () == 0)
258  {
259  NS_LOG_LOGIC ("Nothing extracted.");
260  return 0;
261  }
262  NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_size
263  << ", num pkts in buffer=" << m_data.size ());
264  return outPkt;
265 }
266 
267 } //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:115
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)
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:61
#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:766
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
Ptr< SampleEmitter > s
void IncNextRxSequence(void)
Increment the Next Sequence number.
bool m_gotFin
Did I received FIN packet?
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:51
TypeId SetParent(TypeId tid)
Definition: type-id.cc:631
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