A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tcp-rx-buffer.cc
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
31 TcpRxBuffer::GetTypeId (void)
32 {
33  static TypeId tid = TypeId ("ns3::TcpRxBuffer")
34  .SetParent<Object> ()
35  .AddConstructor<TcpRxBuffer> ()
36  .AddTraceSource ("NextRxSequence",
37  "Next sequence number expected (RCV.NXT)",
38  MakeTraceSourceAccessor (&TcpRxBuffer::m_nextRxSeq))
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  */
50 TcpRxBuffer::TcpRxBuffer (uint32_t n)
51  : m_nextRxSeq (n), m_gotFin (false), m_size (0), m_maxBuffer (32768), m_availBytes (0)
52 {
53 }
54 
55 TcpRxBuffer::~TcpRxBuffer ()
56 {
57 }
58 
59 SequenceNumber32
60 TcpRxBuffer::NextRxSequence (void) const
61 {
62  return m_nextRxSeq;
63 }
64 
65 void
66 TcpRxBuffer::SetNextRxSequence (const SequenceNumber32& s)
67 {
68  m_nextRxSeq = s;
69 }
70 
71 uint32_t
72 TcpRxBuffer::MaxBufferSize (void) const
73 {
74  return m_maxBuffer;
75 }
76 
77 void
78 TcpRxBuffer::SetMaxBufferSize (uint32_t s)
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
90 TcpRxBuffer::Available () const
91 {
92  return m_availBytes;
93 }
94 
95 void
96 TcpRxBuffer::IncNextRxSequence ()
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
106 SequenceNumber32
107 TcpRxBuffer::MaxRxSequence (void) const
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  }
117  return m_nextRxSeq + SequenceNumber32 (m_maxBuffer);
118 }
119 
120 void
121 TcpRxBuffer::SetFinSequence (const SequenceNumber32& s)
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
131 TcpRxBuffer::Finished (void)
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
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
SequenceNumber32 GetSequenceNumber() const
Definition: tcp-header.cc:96
bool Add(Ptr< Packet > p, TcpHeader const &tcph)
#define NS_ASSERT(condition)
Definition: assert.h:64
#define NS_LOG_COMPONENT_DEFINE(name)
Definition: log.h:122
uint32_t GetSize(void) const
Definition: packet.h:620
Ptr< Packet > CreateFragment(uint32_t start, uint32_t length) const
Definition: packet.cc:243
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
Ptr< Packet > Extract(uint32_t maxSize)
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Header for the Transmission Control Protocol.
Definition: tcp-header.h:43