A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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
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.
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:827
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