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