1 /* 2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "BufferQueue.h" 11 12 #include <KernelExport.h> 13 #include <arpa/inet.h> 14 15 16 //#define TRACE_BUFFER_QUEUE 17 #ifdef TRACE_BUFFER_QUEUE 18 # define TRACE(x) dprintf x 19 #else 20 # define TRACE(x) 21 #endif 22 23 #if DEBUG_TCP_BUFFER_QUEUE 24 # define VERIFY() Verify(); 25 #else 26 # define VERIFY() ; 27 #endif 28 29 30 BufferQueue::BufferQueue(size_t maxBytes) 31 : 32 fMaxBytes(maxBytes), 33 fNumBytes(0), 34 fContiguousBytes(0), 35 fFirstSequence(0), 36 fLastSequence(0), 37 fPushPointer(0) 38 { 39 } 40 41 42 BufferQueue::~BufferQueue() 43 { 44 // free up any buffers left in the queue 45 46 net_buffer *buffer; 47 while ((buffer = fList.RemoveHead()) != NULL) { 48 gBufferModule->free(buffer); 49 } 50 } 51 52 53 void 54 BufferQueue::SetMaxBytes(size_t maxBytes) 55 { 56 fMaxBytes = maxBytes; 57 } 58 59 60 void 61 BufferQueue::SetInitialSequence(tcp_sequence sequence) 62 { 63 TRACE(("BufferQueue@%p::SetInitialSequence(%" B_PRIu32 ")\n", this, 64 sequence.Number())); 65 66 fFirstSequence = fLastSequence = sequence; 67 } 68 69 70 71 void 72 BufferQueue::Add(net_buffer *buffer) 73 { 74 Add(buffer, fLastSequence); 75 } 76 77 78 void 79 BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence) 80 { 81 TRACE(("BufferQueue@%p::Add(buffer %p, size %" B_PRIu32 ", sequence %" 82 B_PRIu32 ")\n", this, buffer, buffer->size, sequence.Number())); 83 TRACE((" in: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %lu, cont: " 84 "%lu\n", fFirstSequence.Number(), fLastSequence.Number(), fNumBytes, 85 fContiguousBytes)); 86 VERIFY(); 87 88 if (tcp_sequence(sequence + buffer->size) <= fFirstSequence 89 || buffer->size == 0) { 90 // This buffer does not contain any data of interest 91 gBufferModule->free(buffer); 92 return; 93 } 94 if (sequence < fFirstSequence) { 95 // this buffer contains data that is already long gone - trim it 96 gBufferModule->remove_header(buffer, 97 (fFirstSequence - sequence).Number()); 98 sequence = fFirstSequence; 99 } 100 101 if (fList.IsEmpty() || sequence >= fLastSequence) { 102 // we usually just add the buffer to the end of the queue 103 fList.Add(buffer); 104 buffer->sequence = sequence.Number(); 105 106 if (sequence == fLastSequence 107 && fLastSequence - fFirstSequence == fNumBytes) { 108 // there is no hole in the buffer, we can make the whole buffer 109 // available 110 fContiguousBytes += buffer->size; 111 } 112 113 fLastSequence = sequence + buffer->size; 114 fNumBytes += buffer->size; 115 116 TRACE((" out0: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %" 117 B_PRIuSIZE ", cont: %" B_PRIuSIZE "\n", fFirstSequence.Number(), 118 fLastSequence.Number(), fNumBytes, fContiguousBytes)); 119 VERIFY(); 120 return; 121 } 122 123 if (fLastSequence < sequence + buffer->size) 124 fLastSequence = sequence + buffer->size; 125 126 // find the place where to insert the buffer into the queue 127 128 SegmentList::ReverseIterator iterator = fList.GetReverseIterator(); 129 net_buffer *previous = NULL; 130 net_buffer *next = NULL; 131 while ((previous = iterator.Next()) != NULL) { 132 if (sequence >= previous->sequence) { 133 // The new fragment can be inserted after this one 134 break; 135 } 136 137 next = previous; 138 } 139 140 // check if we have duplicate data, and remove it if that is the case 141 if (previous != NULL) { 142 if (sequence == previous->sequence) { 143 // we already have at least part of this data - ignore new data 144 // whenever it makes sense (because some TCP implementations send 145 // bogus data when probing the window) 146 if (previous->size >= buffer->size) { 147 gBufferModule->free(buffer); 148 buffer = NULL; 149 } else { 150 fList.Remove(previous); 151 fNumBytes -= previous->size; 152 gBufferModule->free(previous); 153 } 154 } else if (tcp_sequence(previous->sequence + previous->size) 155 >= sequence + buffer->size) { 156 // We already know this data 157 gBufferModule->free(buffer); 158 buffer = NULL; 159 } else if (tcp_sequence(previous->sequence + previous->size) 160 > sequence) { 161 // We already have the first part of this buffer 162 gBufferModule->remove_header(buffer, 163 (previous->sequence + previous->size - sequence).Number()); 164 sequence = previous->sequence + previous->size; 165 } 166 } 167 168 // "next" always starts at or after the buffer sequence 169 ASSERT(next == NULL || buffer == NULL || next->sequence >= sequence); 170 171 while (buffer != NULL && next != NULL 172 && tcp_sequence(sequence + buffer->size) > next->sequence) { 173 // we already have at least part of this data 174 if (tcp_sequence(next->sequence + next->size) 175 <= sequence + buffer->size) { 176 net_buffer *remove = next; 177 next = (net_buffer *)next->link.next; 178 179 fList.Remove(remove); 180 fNumBytes -= remove->size; 181 gBufferModule->free(remove); 182 } else if (tcp_sequence(next->sequence) > sequence) { 183 // We have the end of this buffer already 184 gBufferModule->remove_trailer(buffer, 185 (sequence + buffer->size - next->sequence).Number()); 186 } else { 187 // We already have this data 188 gBufferModule->free(buffer); 189 buffer = NULL; 190 } 191 } 192 193 if (buffer == NULL) { 194 TRACE((" out1: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %" 195 B_PRIuSIZE ", cont: %" B_PRIuSIZE "\n", fFirstSequence.Number(), 196 fLastSequence.Number(), fNumBytes, fContiguousBytes)); 197 VERIFY(); 198 return; 199 } 200 201 fList.InsertBefore(next, buffer); 202 buffer->sequence = sequence.Number(); 203 fNumBytes += buffer->size; 204 205 // we might need to update the number of bytes available 206 207 if (fLastSequence - fFirstSequence == fNumBytes) 208 fContiguousBytes = fNumBytes; 209 else if (fFirstSequence + fContiguousBytes == sequence) { 210 // the complicated case: the new segment may have connected almost all 211 // buffers in the queue (but not all, or the above would be true) 212 213 do { 214 fContiguousBytes += buffer->size; 215 216 buffer = (struct net_buffer *)buffer->link.next; 217 } while (buffer != NULL 218 && fFirstSequence + fContiguousBytes == buffer->sequence); 219 } 220 221 TRACE((" out2: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %lu, cont: " 222 "%lu\n", fFirstSequence.Number(), fLastSequence.Number(), fNumBytes, 223 fContiguousBytes)); 224 VERIFY(); 225 } 226 227 228 /*! Removes all data in the queue up to the \a sequence number as specified. 229 230 NOTE: If there are missing segments in the buffers to be removed, 231 fContiguousBytes is not maintained correctly! 232 */ 233 status_t 234 BufferQueue::RemoveUntil(tcp_sequence sequence) 235 { 236 TRACE(("BufferQueue@%p::RemoveUntil(sequence %" B_PRIu32 ")\n", this, 237 sequence.Number())); 238 VERIFY(); 239 240 if (sequence < fFirstSequence) 241 return B_OK; 242 243 SegmentList::Iterator iterator = fList.GetIterator(); 244 tcp_sequence lastRemoved = fFirstSequence; 245 net_buffer *buffer = NULL; 246 while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) { 247 ASSERT(lastRemoved == buffer->sequence); 248 // This assures that the queue has no holes, and fContiguousBytes 249 // is maintained correctly. 250 251 if (sequence >= buffer->sequence + buffer->size) { 252 // remove this buffer completely 253 iterator.Remove(); 254 fNumBytes -= buffer->size; 255 256 fContiguousBytes -= buffer->size; 257 lastRemoved = buffer->sequence + buffer->size; 258 gBufferModule->free(buffer); 259 } else { 260 // remove the header as far as needed 261 size_t size = (sequence - buffer->sequence).Number(); 262 gBufferModule->remove_header(buffer, size); 263 264 buffer->sequence += size; 265 fNumBytes -= size; 266 fContiguousBytes -= size; 267 break; 268 } 269 } 270 271 if (fList.IsEmpty()) 272 fFirstSequence = fLastSequence; 273 else 274 fFirstSequence = fList.Head()->sequence; 275 276 VERIFY(); 277 return B_OK; 278 } 279 280 281 /*! Clones the requested data in the buffer queue into the provided \a buffer. 282 */ 283 status_t 284 BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) 285 { 286 TRACE(("BufferQueue@%p::Get(sequence %" B_PRIu32 ", bytes %lu)\n", this, 287 sequence.Number(), bytes)); 288 VERIFY(); 289 290 if (bytes == 0) 291 return B_OK; 292 293 if (sequence >= fLastSequence || sequence < fFirstSequence) { 294 // we don't have the requested data 295 return B_BAD_VALUE; 296 } 297 if (tcp_sequence(sequence + bytes) > fLastSequence) 298 bytes = (fLastSequence - sequence).Number(); 299 300 size_t bytesLeft = bytes; 301 302 // find first buffer matching the sequence 303 304 SegmentList::Iterator iterator = fList.GetIterator(); 305 net_buffer *source = NULL; 306 while ((source = iterator.Next()) != NULL) { 307 if (sequence < source->sequence + source->size) 308 break; 309 } 310 311 if (source == NULL) 312 panic("we should have had that data..."); 313 if (tcp_sequence(source->sequence) > sequence) { 314 panic("source %p, sequence = %" B_PRIu32 " (%" B_PRIu32 ")\n", source, 315 source->sequence, sequence.Number()); 316 } 317 318 // clone the data 319 320 uint32 offset = (sequence - source->sequence).Number(); 321 322 while (source != NULL && bytesLeft > 0) { 323 size_t size = min_c(source->size - offset, bytesLeft); 324 status_t status = gBufferModule->append_cloned(buffer, source, offset, 325 size); 326 if (status < B_OK) 327 return status; 328 329 bytesLeft -= size; 330 offset = 0; 331 source = iterator.Next(); 332 } 333 334 VERIFY(); 335 return B_OK; 336 } 337 338 339 /*! Creates a new buffer containing \a bytes bytes from the start of the 340 buffer queue. If \a remove is \c true, the data is removed from the 341 queue, if not, the data is cloned from the queue. 342 */ 343 status_t 344 BufferQueue::Get(size_t bytes, bool remove, net_buffer **_buffer) 345 { 346 if (bytes > Available()) 347 bytes = Available(); 348 349 if (bytes == 0) { 350 // we don't need to create a buffer when there is no data 351 *_buffer = NULL; 352 return B_OK; 353 } 354 355 net_buffer *buffer = fList.First(); 356 size_t bytesLeft = bytes; 357 ASSERT(buffer != NULL); 358 359 if (!remove || buffer->size > bytes) { 360 // we need a new buffer 361 buffer = gBufferModule->create(256); 362 if (buffer == NULL) 363 return B_NO_MEMORY; 364 } else { 365 // we can reuse this buffer 366 bytesLeft -= buffer->size; 367 fFirstSequence += buffer->size; 368 369 fList.Remove(buffer); 370 } 371 372 // clone/copy the remaining data 373 374 SegmentList::Iterator iterator = fList.GetIterator(); 375 net_buffer *source = NULL; 376 status_t status = B_OK; 377 while (bytesLeft > 0 && (source = iterator.Next()) != NULL) { 378 size_t size = min_c(source->size, bytesLeft); 379 status = gBufferModule->append_cloned(buffer, source, 0, size); 380 if (status < B_OK) 381 break; 382 383 bytesLeft -= size; 384 385 if (!remove) 386 continue; 387 388 // remove either the whole buffer or only the part we cloned 389 390 fFirstSequence += size; 391 392 if (size == source->size) { 393 iterator.Remove(); 394 gBufferModule->free(source); 395 } else { 396 gBufferModule->remove_header(source, size); 397 source->sequence += size; 398 } 399 } 400 401 if (remove && buffer->size) { 402 fNumBytes -= buffer->size; 403 fContiguousBytes -= buffer->size; 404 } 405 406 // We always return what we got, or else we would lose data 407 if (status < B_OK && buffer->size == 0) { 408 // We could not remove any bytes from the buffer, so 409 // let this call fail. 410 gBufferModule->free(buffer); 411 VERIFY(); 412 return status; 413 } 414 415 *_buffer = buffer; 416 VERIFY(); 417 return B_OK; 418 } 419 420 421 size_t 422 BufferQueue::Available(tcp_sequence sequence) const 423 { 424 if (sequence > (fFirstSequence + fContiguousBytes).Number()) 425 return 0; 426 427 return (fContiguousBytes + fFirstSequence - sequence).Number(); 428 } 429 430 431 void 432 BufferQueue::SetPushPointer() 433 { 434 if (fList.IsEmpty()) 435 fPushPointer = 0; 436 else 437 fPushPointer = fList.Tail()->sequence + fList.Tail()->size; 438 } 439 440 441 int 442 BufferQueue::PopulateSackInfo(tcp_sequence sequence, int maxSackCount, 443 tcp_sack* sacks) 444 { 445 SegmentList::ReverseIterator iterator = fList.GetReverseIterator(); 446 net_buffer* buffer = iterator.Next(); 447 448 int sackCount = 0; 449 TRACE(("BufferQueue::PopulateSackInfo() %" B_PRIu32 "\n", 450 sequence.Number())); 451 while (buffer != NULL && buffer->sequence > sequence) { 452 if (buffer->sequence + buffer->size < sacks[sackCount].left_edge) { 453 if (sackCount + 1 == maxSackCount) 454 break; 455 ++sackCount; 456 sacks[sackCount].left_edge = buffer->sequence; 457 sacks[sackCount].right_edge = buffer->sequence + buffer->size; 458 } else { 459 sacks[sackCount].left_edge = buffer->sequence; 460 if (sacks[sackCount].right_edge == 0) 461 sacks[sackCount].right_edge = buffer->sequence + buffer->size; 462 } 463 464 buffer = iterator.Next(); 465 } 466 467 if (sacks[0].left_edge != 0) { 468 for (int i = 0; i <= sackCount; ++i) { 469 sacks[i].left_edge = htonl(sacks[i].left_edge); 470 sacks[i].right_edge = htonl(sacks[i].right_edge); 471 } 472 ++sackCount; 473 } 474 475 return sackCount; 476 } 477 478 #if DEBUG_TCP_BUFFER_QUEUE 479 480 /*! Perform a sanity check of the whole queue. 481 */ 482 void 483 BufferQueue::Verify() const 484 { 485 ASSERT(Available() == 0 || fList.First() != NULL); 486 487 if (fList.First() == NULL) { 488 ASSERT(fNumBytes == 0); 489 return; 490 } 491 492 SegmentList::ConstIterator iterator = fList.GetIterator(); 493 size_t numBytes = 0; 494 size_t contiguousBytes = 0; 495 bool contiguous = true; 496 tcp_sequence last = fFirstSequence; 497 498 while (net_buffer* buffer = iterator.Next()) { 499 if (contiguous && buffer->sequence == last) 500 contiguousBytes += buffer->size; 501 else 502 contiguous = false; 503 504 ASSERT(last <= buffer->sequence); 505 ASSERT(buffer->size > 0); 506 507 numBytes += buffer->size; 508 last = buffer->sequence + buffer->size; 509 } 510 511 ASSERT(last == fLastSequence); 512 ASSERT(contiguousBytes == fContiguousBytes); 513 ASSERT(numBytes == fNumBytes); 514 } 515 516 517 void 518 BufferQueue::Dump() const 519 { 520 SegmentList::ConstIterator iterator = fList.GetIterator(); 521 int32 number = 0; 522 while (net_buffer* buffer = iterator.Next()) { 523 kprintf(" %" B_PRId32 ". buffer %p, sequence %" B_PRIu32 524 ", size %" B_PRIu32 "\n", ++number, buffer, buffer->sequence, 525 buffer->size); 526 } 527 } 528 529 #endif // DEBUG_TCP_BUFFER_QUEUE 530