A Discrete-Event Network Simulator
API
tcp-tx-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 <iostream>
22 #include <algorithm>
23 #include <cstring>
24 
25 #include "ns3/packet.h"
26 #include "ns3/fatal-error.h"
27 #include "ns3/log.h"
28 
29 #include "tcp-tx-buffer.h"
30 
31 namespace ns3 {
32 
33 NS_LOG_COMPONENT_DEFINE ("TcpTxBuffer");
34 
35 NS_OBJECT_ENSURE_REGISTERED (TcpTxBuffer);
36 
37 TypeId
39 {
40  static TypeId tid = TypeId ("ns3::TcpTxBuffer")
41  .SetParent<Object> ()
42  .AddConstructor<TcpTxBuffer> ()
43  .AddTraceSource ("UnackSequence",
44  "First unacknowledged sequence number (SND.UNA)",
46  "ns3::SequenceNumber32TracedValueCallback")
47  ;
48  return tid;
49 }
50 
51 /* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
52  * there are attributes SndBufSize and RcvBufSize to control the default Tx and
53  * Rx window sizes respectively, with default of 128 KiByte. The attribute
54  * SndBufSize is passed to TcpTxBuffer by TcpSocketBase::SetSndBufSize() and in
55  * turn, TcpTxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
56  * initialized below is insignificant.
57  */
59  : m_firstByteSeq (n), m_size (0), m_maxBuffer (32768), m_data (0)
60 {
61 }
62 
64 {
65 }
66 
69 {
70  return m_firstByteSeq;
71 }
72 
75 {
77 }
78 
79 uint32_t
80 TcpTxBuffer::Size (void) const
81 {
82  return m_size;
83 }
84 
85 uint32_t
87 {
88  return m_maxBuffer;
89 }
90 
91 void
93 {
94  m_maxBuffer = n;
95 }
96 
97 uint32_t
99 {
100  return m_maxBuffer - m_size;
101 }
102 
103 bool
105 {
106  NS_LOG_FUNCTION (this << p);
107  NS_LOG_LOGIC ("Packet of size " << p->GetSize () << " appending to window starting at "
108  << m_firstByteSeq << ", availSize="<< Available ());
109  if (p->GetSize () <= Available ())
110  {
111  if (p->GetSize () > 0)
112  {
113  m_data.push_back (p);
114  m_size += p->GetSize ();
115  NS_LOG_LOGIC ("Updated size=" << m_size << ", lastSeq=" << m_firstByteSeq + SequenceNumber32 (m_size));
116  }
117  return true;
118  }
119  NS_LOG_LOGIC ("Rejected. Not enough room to buffer packet.");
120  return false;
121 }
122 
123 uint32_t
125 {
126  NS_LOG_FUNCTION (this << seq);
127  // Sequence of last byte in buffer
129  // Non-negative size
130  NS_LOG_LOGIC ("HeadSeq=" << m_firstByteSeq << ", lastSeq=" << lastSeq << ", size=" << m_size <<
131  ", returns " << lastSeq - seq);
132  return lastSeq - seq;
133 }
134 
136 TcpTxBuffer::CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq)
137 {
138  NS_LOG_FUNCTION (this << numBytes << seq);
139  uint32_t s = std::min (numBytes, SizeFromSequence (seq)); // Real size to extract. Insure not beyond end of data
140  if (s == 0)
141  {
142  return Create<Packet> (); // Empty packet returned
143  }
144  if (m_data.size () == 0)
145  { // No actual data, just return dummy-data packet of correct size
146  return Create<Packet> (s);
147  }
148 
149  // Extract data from the buffer and return
150  uint32_t offset = seq - m_firstByteSeq.Get ();
151  uint32_t count = 0; // Offset of the first byte of a packet in the buffer
152  uint32_t pktSize = 0;
153  bool beginFound = false;
154  int pktCount = 0;
155  Ptr<Packet> outPacket;
156  NS_LOG_LOGIC ("There are " << m_data.size () << " number of packets in buffer");
157  for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
158  {
159  pktCount++;
160  pktSize = (*i)->GetSize ();
161  if (!beginFound)
162  { // Look for first fragment
163  if (count + pktSize > offset)
164  {
165  NS_LOG_LOGIC ("First byte found in packet #" << pktCount << " at buffer offset " << count
166  << ", packet len=" << pktSize);
167  beginFound = true;
168  uint32_t packetOffset = offset - count;
169  uint32_t fragmentLength = count + pktSize - offset;
170  if (fragmentLength >= s)
171  { // Data to be copied falls entirely in this packet
172  return (*i)->CreateFragment (packetOffset, s);
173  }
174  else
175  { // This packet only fulfills part of the request
176  outPacket = (*i)->CreateFragment (packetOffset, fragmentLength);
177  }
178  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
179  }
180  }
181  else if (count + pktSize >= offset + s)
182  { // Last packet fragment found
183  NS_LOG_LOGIC ("Last byte found in packet #" << pktCount << " at buffer offset " << count
184  << ", packet len=" << pktSize);
185  uint32_t fragmentLength = offset + s - count;
186  Ptr<Packet> endFragment = (*i)->CreateFragment (0, fragmentLength);
187  outPacket->AddAtEnd (endFragment);
188  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
189  break;
190  }
191  else
192  {
193  NS_LOG_LOGIC ("Appending to output the packet #" << pktCount << " of offset " << count << " len=" << pktSize);
194  outPacket->AddAtEnd (*i);
195  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
196  }
197  count += pktSize;
198  }
199  NS_ASSERT (outPacket->GetSize () == s);
200  return outPacket;
201 }
202 
203 void
205 {
206  NS_LOG_FUNCTION (this << seq);
207  m_firstByteSeq = seq;
208 }
209 
210 void
212 {
213  NS_LOG_FUNCTION (this << seq);
214  NS_LOG_LOGIC ("current data size=" << m_size << ", headSeq=" << m_firstByteSeq << ", maxBuffer=" << m_maxBuffer
215  << ", numPkts=" << m_data.size ());
216  // Cases do not need to scan the buffer
217  if (m_firstByteSeq >= seq) return;
218 
219  // Scan the buffer and discard packets
220  uint32_t offset = seq - m_firstByteSeq.Get (); // Number of bytes to remove
221  uint32_t pktSize;
222  NS_LOG_LOGIC ("Offset=" << offset);
223  BufIterator i = m_data.begin ();
224  while (i != m_data.end ())
225  {
226  if (offset > (*i)->GetSize ())
227  { // This packet is behind the seqnum. Remove this packet from the buffer
228  pktSize = (*i)->GetSize ();
229  m_size -= pktSize;
230  offset -= pktSize;
231  m_firstByteSeq += pktSize;
232  i = m_data.erase (i);
233  NS_LOG_LOGIC ("Removed one packet of size " << pktSize << ", offset=" << offset);
234  }
235  else if (offset > 0)
236  { // Part of the packet is behind the seqnum. Fragment
237  pktSize = (*i)->GetSize () - offset;
238  *i = (*i)->CreateFragment (offset, pktSize);
239  m_size -= offset;
240  m_firstByteSeq += offset;
241  NS_LOG_LOGIC ("Fragmented one packet by size " << offset << ", new size=" << pktSize);
242  break;
243  }
244  }
245  // Catching the case of ACKing a FIN
246  if (m_size == 0)
247  {
248  m_firstByteSeq = seq;
249  }
250  NS_LOG_LOGIC ("size=" << m_size << " headSeq=" << m_firstByteSeq << " maxBuffer=" << m_maxBuffer
251  <<" numPkts="<< m_data.size ());
252  NS_ASSERT (m_firstByteSeq == seq);
253 }
254 
255 } // namepsace ns3
uint32_t Size(void) const
Returns total number of bytes in this Tx buffer.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
void DiscardUpTo(const SequenceNumber32 &seq)
Discard data up to but not including this sequence number.
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:44
uint32_t SizeFromSequence(const SequenceNumber32 &seq) const
Returns the number of bytes from the buffer in the range [seq, tailSequence)
SequenceNumber32 HeadSequence(void) const
Returns the first byte's sequence number.
#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
uint32_t MaxBufferSize(void) const
Returns the Tx window size.
#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
T Get(void) const
Get the underlying value.
Definition: traced-value.h:186
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
Create a TraceSourceAccessor which will control access to the underlying trace source.
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 AddAtEnd(Ptr< const Packet > packet)
Concatenate the input packet at the end of the current packet.
Definition: packet.cc:317
TracedValue< SequenceNumber32 > m_firstByteSeq
Sequence number of the first byte in data (SND.UNA)
Ptr< SampleEmitter > s
uint32_t m_size
Number of data bytes.
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
void SetMaxBufferSize(uint32_t n)
Set the Tx window size.
uint32_t Available(void) const
Returns the available capacity in this Tx window.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
bool Add(Ptr< Packet > p)
Append a data packet to the end of the buffer.
static TypeId GetTypeId(void)
Get the type ID.
uint32_t m_maxBuffer
Max number of data bytes in buffer (SND.WND)
A base class which provides memory management and object aggregation.
Definition: object.h:87
TcpTxBuffer(uint32_t n=0)
Constructor.
virtual ~TcpTxBuffer(void)
a unique identifier for an interface.
Definition: type-id.h:51
TypeId SetParent(TypeId tid)
Definition: type-id.cc:631
std::list< Ptr< Packet > >::iterator BufIterator
container for data stored in the buffer
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
SequenceNumber32 TailSequence(void) const
Returns the last byte's sequence number + 1.
std::list< Ptr< Packet > > m_data
Corresponding data (may be null)
void SetHeadSequence(const SequenceNumber32 &seq)
Set the m_firstByteSeq to seq.
Ptr< Packet > CopyFromSequence(uint32_t numBytes, const SequenceNumber32 &seq)
Copy data of size numBytes into a packet, data from the range [seq, seq+numBytes) ...