A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
tcp-tx-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 <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 NS_LOG_COMPONENT_DEFINE ("TcpTxBuffer");
32 
33 namespace ns3 {
34 
35 TypeId
36 TcpTxBuffer::GetTypeId (void)
37 {
38  static TypeId tid = TypeId ("ns3::TcpTxBuffer")
39  .SetParent<Object> ()
40  .AddConstructor<TcpTxBuffer> ()
41  .AddTraceSource ("UnackSequence",
42  "First unacknowledged sequence number (SND.UNA)",
43  MakeTraceSourceAccessor (&TcpTxBuffer::m_firstByteSeq))
44  ;
45  return tid;
46 }
47 
48 /* A user is supposed to create a TcpSocket through a factory. In TcpSocket,
49  * there are attributes SndBufSize and RcvBufSize to control the default Tx and
50  * Rx window sizes respectively, with default of 128 KiByte. The attribute
51  * SndBufSize is passed to TcpTxBuffer by TcpSocketBase::SetSndBufSize() and in
52  * turn, TcpTxBuffer:SetMaxBufferSize(). Therefore, the m_maxBuffer value
53  * initialized below is insignificant.
54  */
55 TcpTxBuffer::TcpTxBuffer (uint32_t n)
56  : m_firstByteSeq (n), m_size (0), m_maxBuffer (32768), m_data (0)
57 {
58 }
59 
60 TcpTxBuffer::~TcpTxBuffer (void)
61 {
62 }
63 
64 SequenceNumber32
66 {
67  return m_firstByteSeq;
68 }
69 
72 {
73  return m_firstByteSeq + SequenceNumber32 (m_size);
74 }
75 
76 uint32_t
77 TcpTxBuffer::Size (void) const
78 {
79  return m_size;
80 }
81 
82 uint32_t
84 {
85  return m_maxBuffer;
86 }
87 
88 void
90 {
91  m_maxBuffer = n;
92 }
93 
94 uint32_t
96 {
97  return m_maxBuffer - m_size;
98 }
99 
100 bool
102 {
103  NS_LOG_FUNCTION (this << p);
104  NS_LOG_LOGIC ("Packet of size " << p->GetSize () << " appending to window starting at "
105  << m_firstByteSeq << ", availSize="<< Available ());
106  if (p->GetSize () <= Available ())
107  {
108  if (p->GetSize () > 0)
109  {
110  m_data.push_back (p);
111  m_size += p->GetSize ();
112  NS_LOG_LOGIC ("Updated size=" << m_size << ", lastSeq=" << m_firstByteSeq + SequenceNumber32 (m_size));
113  }
114  return true;
115  }
116  NS_LOG_LOGIC ("Rejected. Not enough room to buffer packet.");
117  return false;
118 }
119 
120 uint32_t
122 {
123  NS_LOG_FUNCTION (this << seq);
124  // Sequence of last byte in buffer
125  SequenceNumber32 lastSeq = m_firstByteSeq + SequenceNumber32 (m_size);
126  // Non-negative size
127  NS_LOG_LOGIC ("HeadSeq=" << m_firstByteSeq << ", lastSeq=" << lastSeq << ", size=" << m_size <<
128  ", returns " << lastSeq - seq);
129  return lastSeq - seq;
130 }
131 
133 TcpTxBuffer::CopyFromSequence (uint32_t numBytes, const SequenceNumber32& seq)
134 {
135  NS_LOG_FUNCTION (this << numBytes << seq);
136  uint32_t s = std::min (numBytes, SizeFromSequence (seq)); // Real size to extract. Insure not beyond end of data
137  if (s == 0)
138  {
139  return Create<Packet> (); // Empty packet returned
140  }
141  if (m_data.size () == 0)
142  { // No actual data, just return dummy-data packet of correct size
143  return Create<Packet> (s);
144  }
145 
146  // Extract data from the buffer and return
147  uint32_t offset = seq - m_firstByteSeq.Get ();
148  uint32_t count = 0; // Offset of the first byte of a packet in the buffer
149  uint32_t pktSize = 0;
150  bool beginFound = false;
151  int pktCount = 0;
152  Ptr<Packet> outPacket;
153  NS_LOG_LOGIC ("There are " << m_data.size () << " number of packets in buffer");
154  for (BufIterator i = m_data.begin (); i != m_data.end (); ++i)
155  {
156  pktCount++;
157  pktSize = (*i)->GetSize ();
158  if (!beginFound)
159  { // Look for first fragment
160  if (count + pktSize > offset)
161  {
162  NS_LOG_LOGIC ("First byte found in packet #" << pktCount << " at buffer offset " << count
163  << ", packet len=" << pktSize);
164  beginFound = true;
165  uint32_t packetOffset = offset - count;
166  uint32_t fragmentLength = count + pktSize - offset;
167  if (fragmentLength >= s)
168  { // Data to be copied falls entirely in this packet
169  return (*i)->CreateFragment (packetOffset, s);
170  }
171  else
172  { // This packet only fulfills part of the request
173  outPacket = (*i)->CreateFragment (packetOffset, fragmentLength);
174  }
175  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
176  }
177  }
178  else if (count + pktSize >= offset + s)
179  { // Last packet fragment found
180  NS_LOG_LOGIC ("Last byte found in packet #" << pktCount << " at buffer offset " << count
181  << ", packet len=" << pktSize);
182  uint32_t fragmentLength = offset + s - count;
183  Ptr<Packet> endFragment = (*i)->CreateFragment (0, fragmentLength);
184  outPacket->AddAtEnd (endFragment);
185  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
186  break;
187  }
188  else
189  {
190  NS_LOG_LOGIC ("Appending to output the packet #" << pktCount << " of offset " << count << " len=" << pktSize);
191  outPacket->AddAtEnd (*i);
192  NS_LOG_LOGIC ("Output packet is now of size " << outPacket->GetSize ());
193  }
194  count += pktSize;
195  }
196  NS_ASSERT (outPacket->GetSize () == s);
197  return outPacket;
198 }
199 
200 void
202 {
203  NS_LOG_FUNCTION (this << seq);
204  m_firstByteSeq = seq;
205 }
206 
207 void
209 {
210  NS_LOG_FUNCTION (this << seq);
211  NS_LOG_LOGIC ("current data size=" << m_size << ", headSeq=" << m_firstByteSeq << ", maxBuffer=" << m_maxBuffer
212  << ", numPkts=" << m_data.size ());
213  // Cases do not need to scan the buffer
214  if (m_firstByteSeq >= seq) return;
215 
216  // Scan the buffer and discard packets
217  uint32_t offset = seq - m_firstByteSeq.Get (); // Number of bytes to remove
218  uint32_t pktSize;
219  NS_LOG_LOGIC ("Offset=" << offset);
220  BufIterator i = m_data.begin ();
221  while (i != m_data.end ())
222  {
223  if (offset > (*i)->GetSize ())
224  { // This packet is behind the seqnum. Remove this packet from the buffer
225  pktSize = (*i)->GetSize ();
226  m_size -= pktSize;
227  offset -= pktSize;
228  m_firstByteSeq += pktSize;
229  i = m_data.erase (i);
230  NS_LOG_LOGIC ("Removed one packet of size " << pktSize << ", offset=" << offset);
231  }
232  else if (offset > 0)
233  { // Part of the packet is behind the seqnum. Fragment
234  pktSize = (*i)->GetSize () - offset;
235  *i = (*i)->CreateFragment (offset, pktSize);
236  m_size -= offset;
237  m_firstByteSeq += offset;
238  NS_LOG_LOGIC ("Fragmented one packet by size " << offset << ", new size=" << pktSize);
239  break;
240  }
241  }
242  // Catching the case of ACKing a FIN
243  if (m_size == 0)
244  {
245  m_firstByteSeq = seq;
246  }
247  NS_LOG_LOGIC ("size=" << m_size << " headSeq=" << m_firstByteSeq << " maxBuffer=" << m_maxBuffer
248  <<" numPkts="<< m_data.size ());
249  NS_ASSERT (m_firstByteSeq == seq);
250 }
251 
252 } // namepsace ns3
uint32_t Size(void) const
#define NS_LOG_FUNCTION(parameters)
Definition: log.h:311
void DiscardUpTo(const SequenceNumber32 &seq)
uint32_t SizeFromSequence(const SequenceNumber32 &seq) const
SequenceNumber32 HeadSequence(void) const
#define NS_ASSERT(condition)
Definition: assert.h:64
uint32_t MaxBufferSize(void) const
#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
void AddAtEnd(Ptr< const Packet > packet)
Definition: packet.cc:334
#define NS_LOG_LOGIC(msg)
Definition: log.h:334
void SetMaxBufferSize(uint32_t n)
uint32_t Available(void) const
Ptr< const TraceSourceAccessor > MakeTraceSourceAccessor(T a)
bool Add(Ptr< Packet > p)
SequenceNumber32 TailSequence(void) const
void SetHeadSequence(const SequenceNumber32 &seq)
Ptr< Packet > CopyFromSequence(uint32_t numBytes, const SequenceNumber32 &seq)