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 NS_LOG_COMPONENT_DEFINE ("TcpRxBuffer");
27 
28 namespace ns3 {
29 
30 TypeId
32 {
33  static TypeId tid = TypeId ("ns3::TcpRxBuffer")
34  .SetParent<Object> ()
35  .AddConstructor<TcpRxBuffer> ()
36  .AddTraceSource ("NextRxSequence",
37  "Next sequence number expected (RCV.NXT)",
39  ;
40  return tid;
41 }
42 
43 /* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
44  * there are attributes SndBufSize and RcvBufSize to control the default Tx and
45  * Rx window sizes respectively, with default of 128 KiByte. The attribute
46  * RcvBufSize is passed to TcpRxBuffer by TcpSocketBase::SetRcvBufSize() and in
47  * turn, TcpRxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
48  * initialized below is insignificant.
49  */
51  : m_nextRxSeq (n), m_gotFin (false), m_size (0), m_maxBuffer (32768), m_availBytes (0)
52 {
53 }
54 
56 {
57 }
58 
61 {
62  return m_nextRxSeq;
63 }
64 
65 void
67 {
68  m_nextRxSeq = s;
69 }
70 
71 uint32_t
73 {
74  return m_maxBuffer;
75 }
76 
77 void
79 {
80  m_maxBuffer = s;
81 }
82 
83 uint32_t
84 TcpRxBuffer::Size (void) const
85 {
86  return m_size;
87 }
88 
89 uint32_t
91 {
92  return m_availBytes;
93 }
94 
95 void
97 {
98  NS_LOG_FUNCTION (this);
99  // Increment nextRxSeq is valid only if we don't have any data buffered,
100  // this is supposed to be called only during the three-way handshake
101  NS_ASSERT (m_size == 0);
102  m_nextRxSeq++;
103 }
104 
105 // Return the lowest sequence number that this TcpRxBuffer cannot accept
108 {
109  if (m_gotFin)
110  { // No data allowed beyond FIN
111  return m_finSeq;
112  }
113  else if (m_data.size ())
114  { // No data allowed beyond Rx window allowed
115  return m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
116  }
118 }
119 
120 void
122 {
123  NS_LOG_FUNCTION (this);
124 
125  m_gotFin = true;
126  m_finSeq = s;
127  if (m_nextRxSeq == m_finSeq) ++m_nextRxSeq;
128 }
129 
130 bool
132 {
133  return (m_gotFin && m_finSeq < m_nextRxSeq);
134 }
135 
136 bool
138 {
139  NS_LOG_FUNCTION (this << p << tcph);
140 
141  uint32_t pktSize = p->GetSize ();
142  SequenceNumber32 headSeq = tcph.GetSequenceNumber ();
143  SequenceNumber32 tailSeq = headSeq + SequenceNumber32 (pktSize);
144  NS_LOG_LOGIC ("Add pkt " << p << " len=" << pktSize << " seq=" << headSeq
145  << ", when NextRxSeq=" << m_nextRxSeq << ", buffsize=" << m_size);
146 
147  // Trim packet to fit Rx window specification
148  if (headSeq < m_nextRxSeq) headSeq = m_nextRxSeq;
149  if (m_data.size ())
150  {
151  SequenceNumber32 maxSeq = m_data.begin ()->first + SequenceNumber32 (m_maxBuffer);
152  if (maxSeq < tailSeq) tailSeq = maxSeq;
153  if (tailSeq < headSeq) headSeq = tailSeq;
154  }
155  // Remove overlapped bytes from packet
156  BufIterator i = m_data.begin ();
157  while (i != m_data.end () && i->first <= tailSeq)
158  {
159  SequenceNumber32 lastByteSeq = i->first + SequenceNumber32 (i->second->GetSize ());
160  if (lastByteSeq > headSeq)
161  {
162  if (i->first > headSeq && lastByteSeq < tailSeq)
163  { // Rare case: Existing packet is embedded fully in the new packet
164  m_size -= i->second->GetSize ();
165  m_data.erase (i++);
166  continue;
167  }
168  if (i->first <= headSeq)
169  { // Incoming head is overlapped
170  headSeq = lastByteSeq;
171  }
172  if (lastByteSeq >= tailSeq)
173  { // Incoming tail is overlapped
174  tailSeq = i->first;
175  }
176  }
177  ++i;
178  }
179  // We now know how much we are going to store, trim the packet
180  if (headSeq >= tailSeq)
181  {
182  NS_LOG_LOGIC ("Nothing to buffer");
183  return false; // Nothing to buffer anyway
184  }
185  else
186  {
187  uint32_t start = headSeq - tcph.GetSequenceNumber ();
188  uint32_t length = tailSeq - headSeq;
189  p = p->CreateFragment (start, length);
190  NS_ASSERT (length == p->GetSize ());
191  }
192  // Insert packet into buffer
193  NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet
194  m_data [ headSeq ] = p;
195  NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize ());
196  // Update variables
197  m_size += p->GetSize (); // Occupancy
198  for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
199  {
200  if (i->first < m_nextRxSeq)
201  {
202  continue;
203  }
204  else if (i->first > m_nextRxSeq)
205  {
206  break;
207  };
208  m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ());
209  m_availBytes += i->second->GetSize ();
210  }
211  NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_nextRxSeq);
212  if (m_gotFin && m_nextRxSeq == m_finSeq)
213  { // Account for the FIN packet
214  ++m_nextRxSeq;
215  };
216  return true;
217 }
218 
220 TcpRxBuffer::Extract (uint32_t maxSize)
221 {
222  NS_LOG_FUNCTION (this << maxSize);
223 
224  uint32_t extractSize = std::min (maxSize, m_availBytes);
225  NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuffer of size=" << m_size);
226  if (extractSize == 0) return 0; // No contiguous block to return
227  NS_ASSERT (m_data.size ()); // At least we have something to extract
228  Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the data to return
229  BufIterator i;
230  while (extractSize)
231  { // Check the buffered data for delivery
232  i = m_data.begin ();
233  NS_ASSERT (i->first <= m_nextRxSeq); // in-sequence data expected
234  // Check if we send the whole pkt or just a partial
235  uint32_t pktSize = i->second->GetSize ();
236  if (pktSize <= extractSize)
237  { // Whole packet is extracted
238  outPkt->AddAtEnd (i->second);
239  m_data.erase (i);
240  m_size -= pktSize;
241  m_availBytes -= pktSize;
242  extractSize -= pktSize;
243  }
244  else
245  { // Partial is extracted and done
246  outPkt->AddAtEnd (i->second->CreateFragment (0, extractSize));
247  m_data[i->first + SequenceNumber32 (extractSize)] = i->second->CreateFragment (extractSize, pktSize - extractSize);
248  m_data.erase (i);
249  m_size -= extractSize;
250  m_availBytes -= extractSize;
251  extractSize = 0;
252  }
253  }
254  if (outPkt->GetSize () == 0)
255  {
256  NS_LOG_LOGIC ("Nothing extracted.");
257  return 0;
258  }
259  NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_size
260  << ", num pkts in buffer=" << m_data.size ());
261  return outPkt;
262 }
263 
264 } //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)
Definition: log.h:345
SequenceNumber32 GetSequenceNumber() const
Definition: tcp-header.cc:97
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...
TracedValue< SequenceNumber32 > m_nextRxSeq
Seqnum of the first missing byte in data (RCV.NXT)
uint32_t Available() const
Get the actual number of bytes available to be read.
#define NS_ASSERT(condition)
Definition: assert.h:64
uint32_t GetSize(void) const
Definition: packet.h:650
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.
SequenceNumber< uint32_t, int32_t > SequenceNumber32
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)
Definition: log.h:368
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.
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Header for the Transmission Control Protocol.
Definition: tcp-header.h:43
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:63
uint32_t Size(void) const
Get the actual buffer occupancy.
a unique identifier for an interface.
Definition: type-id.h:49
TypeId SetParent(TypeId tid)
Definition: type-id.cc:611
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
NS_LOG_COMPONENT_DEFINE("TcpRxBuffer")