OLD | NEW |
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ | 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
2 /* | 2 /* |
3 * Copyright (c) 2010 Adrian Sai-wah Tam | 3 * Copyright (c) 2010 Adrian Sai-wah Tam |
4 * | 4 * |
5 * This program is free software; you can redistribute it and/or modify | 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 | 6 * it under the terms of the GNU General Public License version 2 as |
7 * published by the Free Software Foundation; | 7 * published by the Free Software Foundation; |
8 * | 8 * |
9 * This program is distributed in the hope that it will be useful, | 9 * This program is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 else | 189 else |
190 { | 190 { |
191 uint32_t start = headSeq - tcph.GetSequenceNumber (); | 191 uint32_t start = headSeq - tcph.GetSequenceNumber (); |
192 uint32_t length = tailSeq - headSeq; | 192 uint32_t length = tailSeq - headSeq; |
193 p = p->CreateFragment (start, length); | 193 p = p->CreateFragment (start, length); |
194 NS_ASSERT (length == p->GetSize ()); | 194 NS_ASSERT (length == p->GetSize ()); |
195 } | 195 } |
196 // Insert packet into buffer | 196 // Insert packet into buffer |
197 NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet | 197 NS_ASSERT (m_data.find (headSeq) == m_data.end ()); // Shouldn't be there yet |
198 m_data [ headSeq ] = p; | 198 m_data [ headSeq ] = p; |
| 199 |
| 200 if (headSeq > m_nextRxSeq) |
| 201 { |
| 202 // Generate a new SACK block |
| 203 UpdateSackList (headSeq, tailSeq); |
| 204 } |
| 205 |
199 NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize
()); | 206 NS_LOG_LOGIC ("Buffered packet of seqno=" << headSeq << " len=" << p->GetSize
()); |
200 // Update variables | 207 // Update variables |
201 m_size += p->GetSize (); // Occupancy | 208 m_size += p->GetSize (); // Occupancy |
202 for (BufIterator i = m_data.begin (); i != m_data.end (); ++i) | 209 for (BufIterator i = m_data.begin (); i != m_data.end (); ++i) |
203 { | 210 { |
204 if (i->first < m_nextRxSeq) | 211 if (i->first < m_nextRxSeq) |
205 { | 212 { |
206 continue; | 213 continue; |
207 } | 214 } |
208 else if (i->first > m_nextRxSeq) | 215 else if (i->first > m_nextRxSeq) |
209 { | 216 { |
210 break; | 217 break; |
211 }; | 218 }; |
212 m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ()); | 219 m_nextRxSeq = i->first + SequenceNumber32 (i->second->GetSize ()); |
213 m_availBytes += i->second->GetSize (); | 220 m_availBytes += i->second->GetSize (); |
| 221 ClearSackList (m_nextRxSeq); |
214 } | 222 } |
215 NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_next
RxSeq); | 223 NS_LOG_LOGIC ("Updated buffer occupancy=" << m_size << " nextRxSeq=" << m_next
RxSeq); |
216 if (m_gotFin && m_nextRxSeq == m_finSeq) | 224 if (m_gotFin && m_nextRxSeq == m_finSeq) |
217 { // Account for the FIN packet | 225 { // Account for the FIN packet |
218 ++m_nextRxSeq; | 226 ++m_nextRxSeq; |
219 }; | 227 }; |
220 return true; | 228 return true; |
221 } | 229 } |
222 | 230 |
| 231 void |
| 232 TcpRxBuffer::UpdateSackList (const SequenceNumber32 &head, const SequenceNumber3
2 &tail) |
| 233 { |
| 234 NS_LOG_FUNCTION (this << head << tail); |
| 235 NS_ASSERT (head > m_nextRxSeq); |
| 236 |
| 237 TcpOptionSack::SackBlock current; |
| 238 current.first = head; |
| 239 current.second = tail; |
| 240 |
| 241 // The block "current" has been safely stored. Now we need to build the SACK |
| 242 // list, to be advertised. From RFC 2018: |
| 243 // (a) The first SACK block (i.e., the one immediately following the |
| 244 // kind and length fields in the option) MUST specify the contiguous |
| 245 // block of data containing the segment which triggered this ACK, |
| 246 // unless that segment advanced the Acknowledgment Number field in |
| 247 // the header. This assures that the ACK with the SACK option |
| 248 // reflects the most recent change in the data receiver's buffer |
| 249 // queue. |
| 250 // |
| 251 // (b) The data receiver SHOULD include as many distinct SACK blocks as |
| 252 // possible in the SACK option. Note that the maximum available |
| 253 // option space may not be sufficient to report all blocks present in |
| 254 // the receiver's queue. |
| 255 // |
| 256 // (c) The SACK option SHOULD be filled out by repeating the most |
| 257 // recently reported SACK blocks (based on first SACK blocks in |
| 258 // previous SACK options) that are not subsets of a SACK block |
| 259 // already included in the SACK option being constructed. This |
| 260 // assures that in normal operation, any segment remaining part of a |
| 261 // non-contiguous block of data held by the data receiver is reported |
| 262 // in at least three successive SACK options, even for large-window |
| 263 // TCP implementations [RFC1323]). After the first SACK block, the |
| 264 // following SACK blocks in the SACK option may be listed in |
| 265 // arbitrary order. |
| 266 |
| 267 m_sackList.push_front (current); |
| 268 |
| 269 // We have inserted the block at the beginning of the list. Now, we should |
| 270 // check if any existing blocks overlap with that. |
| 271 bool updated = false; |
| 272 TcpOptionSack::SackList::iterator it = m_sackList.begin (); |
| 273 TcpOptionSack::SackBlock begin = *it; |
| 274 TcpOptionSack::SackBlock merged; |
| 275 ++it; |
| 276 |
| 277 // Iterates until we examined all blocks in the list (maximum 4) |
| 278 while (it != m_sackList.end ()) |
| 279 { |
| 280 TcpOptionSack::SackBlock current = *it; |
| 281 |
| 282 // This is a left merge: |
| 283 // [current_first; current_second] [beg_first; beg_second] |
| 284 if (begin.first == current.second) |
| 285 { |
| 286 NS_ASSERT (current.first < begin.second); |
| 287 merged = TcpOptionSack::SackBlock (current.first, begin.second); |
| 288 updated = true; |
| 289 } |
| 290 // while this is a right merge |
| 291 // [begin_first; begin_second] [current_first; current_second] |
| 292 else if (begin.second == current.first) |
| 293 { |
| 294 NS_ASSERT (begin.first < current.second); |
| 295 merged = TcpOptionSack::SackBlock (begin.first, current.second); |
| 296 updated = true; |
| 297 } |
| 298 |
| 299 // If we have merged the blocks (and the result is in merged) we should |
| 300 // delete the current block (it), the first block, and insert the merged |
| 301 // one at the beginning. |
| 302 if (updated) |
| 303 { |
| 304 m_sackList.erase (it); |
| 305 m_sackList.pop_front (); |
| 306 m_sackList.push_front (merged); |
| 307 it = m_sackList.begin (); |
| 308 begin = *it; |
| 309 updated = false; |
| 310 } |
| 311 |
| 312 ++it; |
| 313 } |
| 314 |
| 315 // Since the maximum blocks that fits into a TCP header are 4, there's no |
| 316 // point on maintaining the others. |
| 317 if (m_sackList.size () > 4) |
| 318 { |
| 319 m_sackList.pop_back (); |
| 320 } |
| 321 |
| 322 // Please note that, if a block b is discarded and then a block contiguos |
| 323 // to b is received, only that new block (without the b part) is reported. |
| 324 // This is perfectly fine for the RFC point (a), given that we do not report a
ny |
| 325 // overlapping blocks shortly after. |
| 326 } |
| 327 |
| 328 void |
| 329 TcpRxBuffer::ClearSackList (const SequenceNumber32 &seq) |
| 330 { |
| 331 NS_LOG_FUNCTION (this << seq); |
| 332 |
| 333 TcpOptionSack::SackList::iterator it; |
| 334 for (it = m_sackList.begin (); it != m_sackList.end (); ++it) |
| 335 { |
| 336 TcpOptionSack::SackBlock block = *it; |
| 337 NS_ASSERT (block.first < block.second); |
| 338 |
| 339 if (block.second <= seq) |
| 340 { |
| 341 it = m_sackList.erase (it); |
| 342 } |
| 343 } |
| 344 } |
| 345 |
| 346 TcpOptionSack::SackList |
| 347 TcpRxBuffer::GetSackList () const |
| 348 { |
| 349 return m_sackList; |
| 350 } |
| 351 |
223 Ptr<Packet> | 352 Ptr<Packet> |
224 TcpRxBuffer::Extract (uint32_t maxSize) | 353 TcpRxBuffer::Extract (uint32_t maxSize) |
225 { | 354 { |
226 NS_LOG_FUNCTION (this << maxSize); | 355 NS_LOG_FUNCTION (this << maxSize); |
227 | 356 |
228 uint32_t extractSize = std::min (maxSize, m_availBytes); | 357 uint32_t extractSize = std::min (maxSize, m_availBytes); |
229 NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuff
er of size=" << m_size); | 358 NS_LOG_LOGIC ("Requested to extract " << extractSize << " bytes from TcpRxBuff
er of size=" << m_size); |
230 if (extractSize == 0) return 0; // No contiguous block to return | 359 if (extractSize == 0) return 0; // No contiguous block to return |
231 NS_ASSERT (m_data.size ()); // At least we have something to extract | 360 NS_ASSERT (m_data.size ()); // At least we have something to extract |
232 Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the da
ta to return | 361 Ptr<Packet> outPkt = Create<Packet> (); // The packet that contains all the da
ta to return |
(...skipping 26 matching lines...) Expand all Loading... |
259 { | 388 { |
260 NS_LOG_LOGIC ("Nothing extracted."); | 389 NS_LOG_LOGIC ("Nothing extracted."); |
261 return 0; | 390 return 0; |
262 } | 391 } |
263 NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_s
ize | 392 NS_LOG_LOGIC ("Extracted " << outPkt->GetSize ( ) << " bytes, bufsize=" << m_s
ize |
264 << ", num pkts in buffer=" << m_data.size ()); | 393 << ", num pkts in buffer=" << m_data.size ()); |
265 return outPkt; | 394 return outPkt; |
266 } | 395 } |
267 | 396 |
268 } //namepsace ns3 | 397 } //namepsace ns3 |
OLD | NEW |