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 * Ingo Weinhold, ingo_weinhold@gmx.de 8 */ 9 10 #include "utility.h" 11 12 #include <net_buffer.h> 13 #include <slab/Slab.h> 14 #include <tracing.h> 15 #include <util/list.h> 16 17 #include <ByteOrder.h> 18 #include <debug.h> 19 #include <KernelExport.h> 20 #include <util/DoublyLinkedList.h> 21 22 #include <algorithm> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <sys/param.h> 26 #include <sys/uio.h> 27 28 #include "ancillary_data.h" 29 30 #include "paranoia_config.h" 31 32 33 //#define TRACE_BUFFER 34 #ifdef TRACE_BUFFER 35 # define TRACE(x) dprintf x 36 #else 37 # define TRACE(x) ; 38 #endif 39 40 #define BUFFER_SIZE 2048 41 // maximum implementation derived buffer size is 65536 42 43 //#define ENABLE_DEBUGGER_COMMANDS 1 44 #define PARANOID_BUFFER_CHECK NET_BUFFER_PARANOIA 45 46 #define COMPONENT_PARANOIA_LEVEL NET_BUFFER_PARANOIA 47 #include <debug_paranoia.h> 48 49 #define DATA_NODE_READ_ONLY 0x1 50 51 struct header_space { 52 uint16 size; 53 uint16 free; 54 }; 55 56 struct free_data { 57 struct free_data* next; 58 uint16 size; 59 }; 60 61 struct data_header { 62 int32 ref_count; 63 addr_t physical_address; 64 free_data* first_free; 65 uint8* data_end; 66 header_space space; 67 uint16 tail_space; 68 }; 69 70 struct data_node { 71 struct list_link link; 72 struct data_header* header; 73 struct data_header* located; 74 size_t offset; // the net_buffer-wide offset of this node 75 uint8* start; // points to the start of the data 76 uint16 flags; 77 uint16 used; // defines how much memory is used by this node 78 79 uint16 HeaderSpace() const 80 { 81 if ((flags & DATA_NODE_READ_ONLY) != 0) 82 return 0; 83 return header->space.free; 84 } 85 86 void AddHeaderSpace(uint16 toAdd) 87 { 88 if ((flags & DATA_NODE_READ_ONLY) == 0) { 89 header->space.size += toAdd; 90 header->space.free += toAdd; 91 } 92 } 93 94 void SubtractHeaderSpace(uint16 toSubtract) 95 { 96 if ((flags & DATA_NODE_READ_ONLY) == 0) { 97 header->space.size -= toSubtract; 98 header->space.free -= toSubtract; 99 } 100 } 101 102 uint16 TailSpace() const 103 { 104 if ((flags & DATA_NODE_READ_ONLY) != 0) 105 return 0; 106 return header->tail_space; 107 } 108 109 void SetTailSpace(uint16 space) 110 { 111 if ((flags & DATA_NODE_READ_ONLY) == 0) 112 header->tail_space = space; 113 } 114 115 void FreeSpace() 116 { 117 if ((flags & DATA_NODE_READ_ONLY) == 0) { 118 uint16 space = used + header->tail_space; 119 header->space.size += space; 120 header->space.free += space; 121 header->tail_space = 0; 122 } 123 } 124 }; 125 126 struct net_buffer_private : net_buffer { 127 struct list buffers; 128 data_header* allocation_header; 129 // the current place where we allocate header space (nodes, ...) 130 ancillary_data_container* ancillary_data; 131 132 struct { 133 struct sockaddr_storage source; 134 struct sockaddr_storage destination; 135 } storage; 136 }; 137 138 139 #define DATA_HEADER_SIZE _ALIGN(sizeof(data_header)) 140 #define DATA_NODE_SIZE _ALIGN(sizeof(data_node)) 141 #define MAX_FREE_BUFFER_SIZE (BUFFER_SIZE - DATA_HEADER_SIZE) 142 143 144 static object_cache* sNetBufferCache; 145 static object_cache* sDataNodeCache; 146 147 148 static status_t append_data(net_buffer* buffer, const void* data, size_t size); 149 static status_t trim_data(net_buffer* _buffer, size_t newSize); 150 static status_t remove_header(net_buffer* _buffer, size_t bytes); 151 static status_t remove_trailer(net_buffer* _buffer, size_t bytes); 152 static status_t append_cloned_data(net_buffer* _buffer, net_buffer* _source, 153 uint32 offset, size_t bytes); 154 static status_t read_data(net_buffer* _buffer, size_t offset, void* data, 155 size_t size); 156 157 158 #if ENABLE_DEBUGGER_COMMANDS 159 static vint32 sAllocatedDataHeaderCount = 0; 160 static vint32 sAllocatedNetBufferCount = 0; 161 static vint32 sEverAllocatedDataHeaderCount = 0; 162 static vint32 sEverAllocatedNetBufferCount = 0; 163 #endif 164 165 166 #if NET_BUFFER_TRACING 167 168 169 namespace NetBufferTracing { 170 171 172 class NetBufferTraceEntry : public AbstractTraceEntry { 173 public: 174 NetBufferTraceEntry(net_buffer* buffer) 175 : 176 fBuffer(buffer) 177 { 178 #if NET_BUFFER_TRACING_STACK_TRACE 179 fStackTrace = capture_tracing_stack_trace( 180 NET_BUFFER_TRACING_STACK_TRACE, 0, false); 181 #endif 182 } 183 184 #if NET_BUFFER_TRACING_STACK_TRACE 185 virtual void DumpStackTrace(TraceOutput& out) 186 { 187 out.PrintStackTrace(fStackTrace); 188 } 189 #endif 190 191 protected: 192 net_buffer* fBuffer; 193 #if NET_BUFFER_TRACING_STACK_TRACE 194 tracing_stack_trace* fStackTrace; 195 #endif 196 }; 197 198 199 class Create : public NetBufferTraceEntry { 200 public: 201 Create(size_t headerSpace, net_buffer* buffer) 202 : 203 NetBufferTraceEntry(buffer), 204 fHeaderSpace(headerSpace) 205 { 206 Initialized(); 207 } 208 209 virtual void AddDump(TraceOutput& out) 210 { 211 out.Print("net buffer create: header space: %lu -> buffer: %p", 212 fHeaderSpace, fBuffer); 213 } 214 215 private: 216 size_t fHeaderSpace; 217 }; 218 219 220 class Free : public NetBufferTraceEntry { 221 public: 222 Free(net_buffer* buffer) 223 : 224 NetBufferTraceEntry(buffer) 225 { 226 Initialized(); 227 } 228 229 virtual void AddDump(TraceOutput& out) 230 { 231 out.Print("net buffer free: buffer: %p", fBuffer); 232 } 233 }; 234 235 236 class Duplicate : public NetBufferTraceEntry { 237 public: 238 Duplicate(net_buffer* buffer, net_buffer* clone) 239 : 240 NetBufferTraceEntry(buffer), 241 fClone(clone) 242 { 243 Initialized(); 244 } 245 246 virtual void AddDump(TraceOutput& out) 247 { 248 out.Print("net buffer dup: buffer: %p -> %p", fBuffer, fClone); 249 } 250 251 private: 252 net_buffer* fClone; 253 }; 254 255 256 class Clone : public NetBufferTraceEntry { 257 public: 258 Clone(net_buffer* buffer, bool shareFreeSpace, net_buffer* clone) 259 : 260 NetBufferTraceEntry(buffer), 261 fClone(clone), 262 fShareFreeSpace(shareFreeSpace) 263 { 264 Initialized(); 265 } 266 267 virtual void AddDump(TraceOutput& out) 268 { 269 out.Print("net buffer clone: buffer: %p, share free space: %s " 270 "-> %p", fBuffer, fShareFreeSpace ? "true" : "false", fClone); 271 } 272 273 private: 274 net_buffer* fClone; 275 bool fShareFreeSpace; 276 }; 277 278 279 class Split : public NetBufferTraceEntry { 280 public: 281 Split(net_buffer* buffer, uint32 offset, net_buffer* newBuffer) 282 : 283 NetBufferTraceEntry(buffer), 284 fNewBuffer(newBuffer), 285 fOffset(offset) 286 { 287 Initialized(); 288 } 289 290 virtual void AddDump(TraceOutput& out) 291 { 292 out.Print("net buffer split: buffer: %p, offset: %lu " 293 "-> %p", fBuffer, fOffset, fNewBuffer); 294 } 295 296 private: 297 net_buffer* fNewBuffer; 298 uint32 fOffset; 299 }; 300 301 302 class Merge : public NetBufferTraceEntry { 303 public: 304 Merge(net_buffer* buffer, net_buffer* otherBuffer, bool after) 305 : 306 NetBufferTraceEntry(buffer), 307 fOtherBuffer(otherBuffer), 308 fAfter(after) 309 { 310 Initialized(); 311 } 312 313 virtual void AddDump(TraceOutput& out) 314 { 315 out.Print("net buffer merge: buffers: %p + %p, after: %s " 316 "-> %p", fBuffer, fOtherBuffer, fAfter ? "true" : "false", 317 fOtherBuffer); 318 } 319 320 private: 321 net_buffer* fOtherBuffer; 322 bool fAfter; 323 }; 324 325 326 class AppendCloned : public NetBufferTraceEntry { 327 public: 328 AppendCloned(net_buffer* buffer, net_buffer* source, uint32 offset, 329 size_t size) 330 : 331 NetBufferTraceEntry(buffer), 332 fSource(source), 333 fOffset(offset), 334 fSize(size) 335 { 336 Initialized(); 337 } 338 339 virtual void AddDump(TraceOutput& out) 340 { 341 out.Print("net buffer append cloned: buffer: %p, from: %p, " 342 "offset: %lu, size: %lu", fBuffer, fSource, fOffset, fSize); 343 } 344 345 private: 346 net_buffer* fSource; 347 uint32 fOffset; 348 size_t fSize; 349 }; 350 351 352 class PrependSize : public NetBufferTraceEntry { 353 public: 354 PrependSize(net_buffer* buffer, size_t size) 355 : 356 NetBufferTraceEntry(buffer), 357 fSize(size) 358 { 359 Initialized(); 360 } 361 362 virtual void AddDump(TraceOutput& out) 363 { 364 out.Print("net buffer prepend size: buffer: %p, size: %lu", fBuffer, 365 fSize); 366 } 367 368 private: 369 size_t fSize; 370 }; 371 372 373 class AppendSize : public NetBufferTraceEntry { 374 public: 375 AppendSize(net_buffer* buffer, size_t size) 376 : 377 NetBufferTraceEntry(buffer), 378 fSize(size) 379 { 380 Initialized(); 381 } 382 383 virtual void AddDump(TraceOutput& out) 384 { 385 out.Print("net buffer append size: buffer: %p, size: %lu", fBuffer, 386 fSize); 387 } 388 389 private: 390 size_t fSize; 391 }; 392 393 394 class RemoveHeader : public NetBufferTraceEntry { 395 public: 396 RemoveHeader(net_buffer* buffer, size_t size) 397 : 398 NetBufferTraceEntry(buffer), 399 fSize(size) 400 { 401 Initialized(); 402 } 403 404 virtual void AddDump(TraceOutput& out) 405 { 406 out.Print("net buffer remove header: buffer: %p, size: %lu", 407 fBuffer, fSize); 408 } 409 410 private: 411 size_t fSize; 412 }; 413 414 415 class Trim : public NetBufferTraceEntry { 416 public: 417 Trim(net_buffer* buffer, size_t size) 418 : 419 NetBufferTraceEntry(buffer), 420 fSize(size) 421 { 422 Initialized(); 423 } 424 425 virtual void AddDump(TraceOutput& out) 426 { 427 out.Print("net buffer trim: buffer: %p, size: %lu", 428 fBuffer, fSize); 429 } 430 431 private: 432 size_t fSize; 433 }; 434 435 436 class Read : public NetBufferTraceEntry { 437 public: 438 Read(net_buffer* buffer, uint32 offset, void* data, size_t size) 439 : 440 NetBufferTraceEntry(buffer), 441 fData(data), 442 fOffset(offset), 443 fSize(size) 444 { 445 Initialized(); 446 } 447 448 virtual void AddDump(TraceOutput& out) 449 { 450 out.Print("net buffer read: buffer: %p, offset: %lu, size: %lu, " 451 "data: %p", fBuffer, fOffset, fSize, fData); 452 } 453 454 private: 455 void* fData; 456 uint32 fOffset; 457 size_t fSize; 458 }; 459 460 461 class Write : public NetBufferTraceEntry { 462 public: 463 Write(net_buffer* buffer, uint32 offset, const void* data, size_t size) 464 : 465 NetBufferTraceEntry(buffer), 466 fData(data), 467 fOffset(offset), 468 fSize(size) 469 { 470 Initialized(); 471 } 472 473 virtual void AddDump(TraceOutput& out) 474 { 475 out.Print("net buffer write: buffer: %p, offset: %lu, size: %lu, " 476 "data: %p", fBuffer, fOffset, fSize, fData); 477 } 478 479 private: 480 const void* fData; 481 uint32 fOffset; 482 size_t fSize; 483 }; 484 485 486 #if NET_BUFFER_TRACING >= 2 487 488 class DataHeaderTraceEntry : public AbstractTraceEntry { 489 public: 490 DataHeaderTraceEntry(data_header* header) 491 : 492 fHeader(header) 493 { 494 } 495 496 protected: 497 data_header* fHeader; 498 }; 499 500 501 class CreateDataHeader : public DataHeaderTraceEntry { 502 public: 503 CreateDataHeader(data_header* header) 504 : 505 DataHeaderTraceEntry(header) 506 { 507 Initialized(); 508 } 509 510 virtual void AddDump(TraceOutput& out) 511 { 512 out.Print("net buffer data header create: header: %p", fHeader); 513 } 514 }; 515 516 517 class AcquireDataHeader : public DataHeaderTraceEntry { 518 public: 519 AcquireDataHeader(data_header* header, int32 refCount) 520 : 521 DataHeaderTraceEntry(header), 522 fRefCount(refCount) 523 { 524 Initialized(); 525 } 526 527 virtual void AddDump(TraceOutput& out) 528 { 529 out.Print("net buffer data header acquire: header: %p " 530 "-> ref count: %ld", fHeader, fRefCount); 531 } 532 533 private: 534 int32 fRefCount; 535 }; 536 537 538 class ReleaseDataHeader : public DataHeaderTraceEntry { 539 public: 540 ReleaseDataHeader(data_header* header, int32 refCount) 541 : 542 DataHeaderTraceEntry(header), 543 fRefCount(refCount) 544 { 545 Initialized(); 546 } 547 548 virtual void AddDump(TraceOutput& out) 549 { 550 out.Print("net buffer data header release: header: %p " 551 "-> ref count: %ld", fHeader, fRefCount); 552 } 553 554 private: 555 int32 fRefCount; 556 }; 557 558 # define T2(x) new(std::nothrow) NetBufferTracing::x 559 #else 560 # define T2(x) 561 #endif // NET_BUFFER_TRACING >= 2 562 563 } // namespace NetBufferTracing 564 565 # define T(x) new(std::nothrow) NetBufferTracing::x 566 567 #else 568 # define T(x) 569 # define T2(x) 570 #endif // NET_BUFFER_TRACING 571 572 573 #if 1 574 static void 575 dump_buffer(net_buffer* _buffer) 576 { 577 net_buffer_private* buffer = (net_buffer_private*)_buffer; 578 579 dprintf("buffer %p, size %ld\n", buffer, buffer->size); 580 data_node* node = NULL; 581 while ((node = (data_node*)list_get_next_item(&buffer->buffers, node)) 582 != NULL) { 583 dprintf(" node %p, offset %lu, used %u, header %u, tail %u, " 584 "header %p\n", node, node->offset, node->used, node->HeaderSpace(), 585 node->TailSpace(), node->header); 586 //dump_block((char*)node->start, node->used, " "); 587 dump_block((char*)node->start, min_c(node->used, 32), " "); 588 } 589 } 590 #endif 591 592 593 #if ENABLE_DEBUGGER_COMMANDS 594 595 static int 596 dump_net_buffer_stats(int argc, char** argv) 597 { 598 kprintf("allocated data headers: %7ld / %7ld\n", sAllocatedDataHeaderCount, 599 sEverAllocatedDataHeaderCount); 600 kprintf("allocated net buffers: %7ld / %7ld\n", sAllocatedNetBufferCount, 601 sEverAllocatedNetBufferCount); 602 return 0; 603 } 604 605 #endif // ENABLE_DEBUGGER_COMMANDS 606 607 608 #if PARANOID_BUFFER_CHECK 609 610 static void 611 check_buffer(net_buffer* _buffer) 612 { 613 net_buffer_private* buffer = (net_buffer_private*)_buffer; 614 615 // sum up the size of all nodes 616 size_t size = 0; 617 618 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 619 while (node != NULL) { 620 if (node->offset != size) { 621 panic("net_buffer %p: bad node %p offset (%lu vs. %lu)", 622 buffer, node, node->offset, size); 623 return; 624 } 625 size += node->used; 626 node = (data_node*)list_get_next_item(&buffer->buffers, node); 627 } 628 629 if (size != buffer->size) { 630 panic("net_buffer %p size != sum of its data node sizes (%lu vs. %lu)", 631 buffer, buffer->size, size); 632 return; 633 } 634 } 635 636 637 #if 0 638 static void 639 check_buffer_contents(net_buffer* buffer, size_t offset, const void* data, 640 size_t size) 641 { 642 void* bufferData = malloc(size); 643 if (bufferData == NULL) 644 return; 645 646 if (read_data(buffer, offset, bufferData, size) == B_OK) { 647 if (memcmp(bufferData, data, size) != 0) { 648 int32 index = 0; 649 while (((uint8*)data)[index] == ((uint8*)bufferData)[index]) 650 index++; 651 panic("check_buffer_contents(): contents check failed at index " 652 "%ld, buffer: %p, offset: %lu, size: %lu", index, buffer, 653 offset, size); 654 } 655 } else { 656 panic("failed to read from buffer %p, offset: %lu, size: %lu", 657 buffer, offset, size); 658 } 659 660 free(bufferData); 661 } 662 663 664 static void 665 check_buffer_contents(net_buffer* buffer, size_t offset, net_buffer* source, 666 size_t sourceOffset, size_t size) 667 { 668 void* bufferData = malloc(size); 669 if (bufferData == NULL) 670 return; 671 672 if (read_data(source, sourceOffset, bufferData, size) == B_OK) { 673 check_buffer_contents(buffer, offset, bufferData, size); 674 } else { 675 panic("failed to read from source buffer %p, offset: %lu, size: %lu", 676 source, sourceOffset, size); 677 } 678 679 free(bufferData); 680 } 681 #endif 682 683 684 # define CHECK_BUFFER(buffer) check_buffer(buffer) 685 #else 686 # define CHECK_BUFFER(buffer) do {} while (false) 687 #endif // !PARANOID_BUFFER_CHECK 688 689 690 static inline data_header* 691 allocate_data_header() 692 { 693 #if ENABLE_DEBUGGER_COMMANDS 694 atomic_add(&sAllocatedDataHeaderCount, 1); 695 atomic_add(&sEverAllocatedDataHeaderCount, 1); 696 #endif 697 return (data_header*)object_cache_alloc(sDataNodeCache, CACHE_DONT_SLEEP); 698 } 699 700 701 static inline net_buffer_private* 702 allocate_net_buffer() 703 { 704 #if ENABLE_DEBUGGER_COMMANDS 705 atomic_add(&sAllocatedNetBufferCount, 1); 706 atomic_add(&sEverAllocatedNetBufferCount, 1); 707 #endif 708 return (net_buffer_private*)object_cache_alloc(sNetBufferCache, 709 CACHE_DONT_SLEEP); 710 } 711 712 713 static inline void 714 free_data_header(data_header* header) 715 { 716 #if ENABLE_DEBUGGER_COMMANDS 717 if (header != NULL) 718 atomic_add(&sAllocatedDataHeaderCount, -1); 719 #endif 720 object_cache_free(sDataNodeCache, header); 721 } 722 723 724 static inline void 725 free_net_buffer(net_buffer_private* buffer) 726 { 727 #if ENABLE_DEBUGGER_COMMANDS 728 if (buffer != NULL) 729 atomic_add(&sAllocatedNetBufferCount, -1); 730 #endif 731 object_cache_free(sNetBufferCache, buffer); 732 } 733 734 735 static data_header* 736 create_data_header(size_t headerSpace) 737 { 738 data_header* header = allocate_data_header(); 739 if (header == NULL) 740 return NULL; 741 742 header->ref_count = 1; 743 header->physical_address = 0; 744 // TODO: initialize this correctly 745 header->space.size = headerSpace; 746 header->space.free = headerSpace; 747 header->data_end = (uint8*)header + DATA_HEADER_SIZE; 748 header->tail_space = (uint8*)header + BUFFER_SIZE - header->data_end 749 - headerSpace; 750 header->first_free = NULL; 751 752 TRACE(("%ld: create new data header %p\n", find_thread(NULL), header)); 753 T2(CreateDataHeader(header)); 754 return header; 755 } 756 757 758 static void 759 release_data_header(data_header* header) 760 { 761 int32 refCount = atomic_add(&header->ref_count, -1); 762 T2(ReleaseDataHeader(header, refCount - 1)); 763 if (refCount != 1) 764 return; 765 766 TRACE(("%ld: free header %p\n", find_thread(NULL), header)); 767 free_data_header(header); 768 } 769 770 771 inline void 772 acquire_data_header(data_header* header) 773 { 774 int32 refCount = atomic_add(&header->ref_count, 1); 775 (void)refCount; 776 T2(AcquireDataHeader(header, refCount + 1)); 777 } 778 779 780 static void 781 free_data_header_space(data_header* header, uint8* data, size_t size) 782 { 783 if (size < sizeof(free_data)) 784 size = sizeof(free_data); 785 786 free_data* freeData = (free_data*)data; 787 freeData->next = header->first_free; 788 freeData->size = size; 789 790 header->first_free = freeData; 791 } 792 793 794 /*! Tries to allocate \a size bytes from the free space in the header. 795 */ 796 static uint8* 797 alloc_data_header_space(data_header* header, size_t size) 798 { 799 if (size < sizeof(free_data)) 800 size = sizeof(free_data); 801 size = _ALIGN(size); 802 803 if (header->first_free != NULL && header->first_free->size >= size) { 804 // the first entry of the header space matches the allocation's needs 805 806 // TODO: If the free space is greater than what shall be allocated, we 807 // leak the remainder of the space. We should only allocate multiples of 808 // _ALIGN(sizeof(free_data)) and split free space in this case. It's not 809 // that pressing, since the only thing allocated ATM are data_nodes, and 810 // thus the free space entries will always have the right size. 811 uint8* data = (uint8*)header->first_free; 812 header->first_free = header->first_free->next; 813 return data; 814 } 815 816 if (header->space.free < size) { 817 // there is no free space left, search free list 818 free_data* freeData = header->first_free; 819 free_data* last = NULL; 820 while (freeData != NULL) { 821 if (last != NULL && freeData->size >= size) { 822 // take this one 823 last->next = freeData->next; 824 return (uint8*)freeData; 825 } 826 827 last = freeData; 828 freeData = freeData->next; 829 } 830 831 return NULL; 832 } 833 834 // allocate new space 835 836 uint8* data = header->data_end; 837 header->data_end += size; 838 header->space.free -= size; 839 840 return data; 841 } 842 843 844 static uint8* 845 alloc_data_header_space(net_buffer_private* buffer, size_t size, 846 data_header** _header = NULL) 847 { 848 // try to allocate in our current allocation header 849 uint8* allocated = alloc_data_header_space(buffer->allocation_header, size); 850 if (allocated == NULL) { 851 // not enough header space left -- create a fresh buffer for headers 852 data_header* header = create_data_header(MAX_FREE_BUFFER_SIZE); 853 if (header == NULL) 854 return NULL; 855 856 // release our reference to the old header -- it will will stay around 857 // until the last reference to it is released 858 release_data_header(buffer->allocation_header); 859 buffer->allocation_header = header; 860 // We keep the initial reference. 861 862 // now the allocation can only fail, if size is too big 863 allocated = alloc_data_header_space(buffer->allocation_header, size); 864 } 865 866 if (_header != NULL) 867 *_header = buffer->allocation_header; 868 869 return allocated; 870 } 871 872 873 static data_node* 874 add_first_data_node(data_header* header) 875 { 876 data_node* node = (data_node*)alloc_data_header_space(header, 877 sizeof(data_node)); 878 if (node == NULL) 879 return NULL; 880 881 TRACE(("%ld: add first data node %p to header %p\n", find_thread(NULL), 882 node, header)); 883 884 acquire_data_header(header); 885 886 memset(node, 0, sizeof(struct data_node)); 887 node->located = header; 888 node->header = header; 889 node->offset = 0; 890 node->start = header->data_end + header->space.free; 891 node->used = 0; 892 node->flags = 0; 893 894 return node; 895 } 896 897 898 static data_node* 899 add_data_node(net_buffer_private* buffer, data_header* header) 900 { 901 data_header* located; 902 data_node* node = (data_node*)alloc_data_header_space(buffer, 903 sizeof(data_node), &located); 904 if (node == NULL) 905 return NULL; 906 907 TRACE(("%ld: add data node %p to header %p\n", find_thread(NULL), node, 908 header)); 909 910 acquire_data_header(header); 911 if (located != header) 912 acquire_data_header(located); 913 914 memset(node, 0, sizeof(struct data_node)); 915 node->located = located; 916 node->header = header; 917 node->flags = 0; 918 return node; 919 } 920 921 922 void 923 remove_data_node(data_node* node) 924 { 925 data_header* located = node->located; 926 927 TRACE(("%ld: remove data node %p from header %p (located %p)\n", 928 find_thread(NULL), node, node->header, located)); 929 930 // Move all used and tail space to the header space, which is useful in case 931 // this is the first node of a buffer (i.e. the header is an allocation 932 // header). 933 node->FreeSpace(); 934 935 if (located != node->header) 936 release_data_header(node->header); 937 938 if (located == NULL) 939 return; 940 941 free_data_header_space(located, (uint8*)node, sizeof(data_node)); 942 943 release_data_header(located); 944 } 945 946 947 static inline data_node* 948 get_node_at_offset(net_buffer_private* buffer, size_t offset) 949 { 950 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 951 while (node->offset + node->used <= offset) { 952 node = (data_node*)list_get_next_item(&buffer->buffers, node); 953 if (node == NULL) 954 return NULL; 955 } 956 957 return node; 958 } 959 960 961 /*! Appends up to \a size bytes from the data of the \a from net_buffer to the 962 \a to net_buffer. The source buffer will remain unchanged. 963 */ 964 static status_t 965 append_data_from_buffer(net_buffer* to, const net_buffer* from, size_t size) 966 { 967 net_buffer_private* source = (net_buffer_private*)from; 968 net_buffer_private* dest = (net_buffer_private*)to; 969 970 if (size > from->size) 971 return B_BAD_VALUE; 972 if (size == 0) 973 return B_OK; 974 975 data_node* nodeTo = get_node_at_offset(source, size); 976 if (nodeTo == NULL) 977 return B_BAD_VALUE; 978 979 data_node* node = (data_node*)list_get_first_item(&source->buffers); 980 if (node == NULL) { 981 CHECK_BUFFER(source); 982 return B_ERROR; 983 } 984 985 while (node != nodeTo) { 986 if (append_data(dest, node->start, node->used) < B_OK) { 987 CHECK_BUFFER(dest); 988 return B_ERROR; 989 } 990 991 node = (data_node*)list_get_next_item(&source->buffers, node); 992 } 993 994 int32 diff = node->offset + node->used - size; 995 if (append_data(dest, node->start, node->used - diff) < B_OK) { 996 CHECK_BUFFER(dest); 997 return B_ERROR; 998 } 999 1000 CHECK_BUFFER(dest); 1001 1002 return B_OK; 1003 } 1004 1005 1006 static void 1007 copy_metadata(net_buffer* destination, const net_buffer* source) 1008 { 1009 memcpy(destination->source, source->source, 1010 min_c(source->source->sa_len, sizeof(sockaddr_storage))); 1011 memcpy(destination->destination, source->destination, 1012 min_c(source->destination->sa_len, sizeof(sockaddr_storage))); 1013 1014 destination->flags = source->flags; 1015 destination->interface = source->interface; 1016 destination->offset = source->offset; 1017 destination->size = source->size; 1018 destination->protocol = source->protocol; 1019 destination->type = source->type; 1020 } 1021 1022 1023 // #pragma mark - module API 1024 1025 1026 static net_buffer* 1027 create_buffer(size_t headerSpace) 1028 { 1029 net_buffer_private* buffer = allocate_net_buffer(); 1030 if (buffer == NULL) 1031 return NULL; 1032 1033 TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer)); 1034 1035 // Make sure headerSpace is valid and at least the initial node fits. 1036 headerSpace = _ALIGN(headerSpace); 1037 if (headerSpace < DATA_NODE_SIZE) 1038 headerSpace = DATA_NODE_SIZE; 1039 else if (headerSpace > MAX_FREE_BUFFER_SIZE) 1040 headerSpace = MAX_FREE_BUFFER_SIZE; 1041 1042 data_header* header = create_data_header(headerSpace); 1043 if (header == NULL) { 1044 free_net_buffer(buffer); 1045 return NULL; 1046 } 1047 buffer->allocation_header = header; 1048 1049 data_node* node = add_first_data_node(header); 1050 1051 list_init(&buffer->buffers); 1052 list_add_item(&buffer->buffers, node); 1053 1054 buffer->ancillary_data = NULL; 1055 1056 buffer->source = (sockaddr*)&buffer->storage.source; 1057 buffer->destination = (sockaddr*)&buffer->storage.destination; 1058 1059 buffer->storage.source.ss_len = 0; 1060 buffer->storage.destination.ss_len = 0; 1061 1062 buffer->interface = NULL; 1063 buffer->offset = 0; 1064 buffer->flags = 0; 1065 buffer->size = 0; 1066 1067 buffer->type = -1; 1068 1069 CHECK_BUFFER(buffer); 1070 CREATE_PARANOIA_CHECK_SET(buffer, "net_buffer"); 1071 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1072 sizeof(buffer->size)); 1073 1074 T(Create(headerSpace, buffer)); 1075 1076 return buffer; 1077 } 1078 1079 1080 static void 1081 free_buffer(net_buffer* _buffer) 1082 { 1083 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1084 1085 TRACE(("%ld: free buffer %p\n", find_thread(NULL), buffer)); 1086 T(Free(buffer)); 1087 1088 CHECK_BUFFER(buffer); 1089 DELETE_PARANOIA_CHECK_SET(buffer); 1090 1091 while (data_node* node 1092 = (data_node*)list_remove_head_item(&buffer->buffers)) { 1093 remove_data_node(node); 1094 } 1095 1096 delete_ancillary_data_container(buffer->ancillary_data); 1097 1098 release_data_header(buffer->allocation_header); 1099 1100 free_net_buffer(buffer); 1101 } 1102 1103 1104 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal 1105 storage; they are completely independent from each other. 1106 */ 1107 static net_buffer* 1108 duplicate_buffer(net_buffer* _buffer) 1109 { 1110 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1111 1112 ParanoiaChecker _(buffer); 1113 1114 TRACE(("%ld: duplicate_buffer(buffer %p)\n", find_thread(NULL), buffer)); 1115 1116 // TODO: We might want to choose a better header space. The minimal 1117 // one doesn't allow to prepend any data without allocating a new header. 1118 // The same holds for appending cloned data. 1119 net_buffer* duplicate = create_buffer(DATA_NODE_SIZE); 1120 if (duplicate == NULL) 1121 return NULL; 1122 1123 TRACE(("%ld: duplicate: %p)\n", find_thread(NULL), duplicate)); 1124 1125 // copy the data from the source buffer 1126 1127 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 1128 while (node != NULL) { 1129 if (append_data(duplicate, node->start, node->used) < B_OK) { 1130 free_buffer(duplicate); 1131 CHECK_BUFFER(buffer); 1132 return NULL; 1133 } 1134 1135 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1136 } 1137 1138 copy_metadata(duplicate, buffer); 1139 1140 CHECK_BUFFER(buffer); 1141 CHECK_BUFFER(duplicate); 1142 RUN_PARANOIA_CHECKS(duplicate); 1143 1144 T(Duplicate(buffer, duplicate)); 1145 1146 return duplicate; 1147 } 1148 1149 1150 /*! Clones the buffer by grabbing another reference to the underlying data. 1151 If that data changes, it will be changed in the clone as well. 1152 1153 If \a shareFreeSpace is \c true, the cloned buffer may claim the free 1154 space in the original buffer as the original buffer can still do. If you 1155 are using this, it's your responsibility that only one of the buffers 1156 will do this. 1157 */ 1158 static net_buffer* 1159 clone_buffer(net_buffer* _buffer, bool shareFreeSpace) 1160 { 1161 // TODO: See, if the commented out code can be fixed in a safe way. We could 1162 // probably place cloned nodes on a header not belonging to our buffer, if 1163 // we don't free the header space for the node when removing it. Otherwise we 1164 // mess with the header's free list which might at the same time be accessed 1165 // by another thread. 1166 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1167 1168 net_buffer* clone = create_buffer(MAX_FREE_BUFFER_SIZE); 1169 if (clone == NULL) 1170 return NULL; 1171 1172 if (append_cloned_data(clone, buffer, 0, buffer->size) != B_OK) { 1173 free_buffer(clone); 1174 return NULL; 1175 } 1176 1177 copy_metadata(clone, buffer); 1178 1179 return clone; 1180 1181 #if 0 1182 ParanoiaChecker _(buffer); 1183 1184 TRACE(("%ld: clone_buffer(buffer %p)\n", find_thread(NULL), buffer)); 1185 1186 net_buffer_private* clone = allocate_net_buffer(); 1187 if (clone == NULL) 1188 return NULL; 1189 1190 TRACE(("%ld: clone: %p\n", find_thread(NULL), buffer)); 1191 1192 data_node* sourceNode = (data_node*)list_get_first_item(&buffer->buffers); 1193 if (sourceNode == NULL) { 1194 free_net_buffer(clone); 1195 return NULL; 1196 } 1197 1198 clone->source = (sockaddr*)&clone->storage.source; 1199 clone->destination = (sockaddr*)&clone->storage.destination; 1200 1201 list_init(&clone->buffers); 1202 1203 // grab reference to this buffer - all additional nodes will get 1204 // theirs in add_data_node() 1205 acquire_data_header(sourceNode->header); 1206 data_node* node = &clone->first_node; 1207 node->header = sourceNode->header; 1208 node->located = NULL; 1209 node->used_header_space = &node->own_header_space; 1210 1211 while (sourceNode != NULL) { 1212 node->start = sourceNode->start; 1213 node->used = sourceNode->used; 1214 node->offset = sourceNode->offset; 1215 1216 if (shareFreeSpace) { 1217 // both buffers could claim the free space - note that this option 1218 // has to be used carefully 1219 node->used_header_space = &sourceNode->header->space; 1220 node->tail_space = sourceNode->tail_space; 1221 } else { 1222 // the free space stays with the original buffer 1223 node->used_header_space->size = 0; 1224 node->used_header_space->free = 0; 1225 node->tail_space = 0; 1226 } 1227 1228 // add node to clone's list of buffers 1229 list_add_item(&clone->buffers, node); 1230 1231 sourceNode = (data_node*)list_get_next_item(&buffer->buffers, 1232 sourceNode); 1233 if (sourceNode == NULL) 1234 break; 1235 1236 node = add_data_node(sourceNode->header); 1237 if (node == NULL) { 1238 // There was not enough space left for another node in this buffer 1239 // TODO: handle this case! 1240 panic("clone buffer hits size limit... (fix me)"); 1241 free_net_buffer(clone); 1242 return NULL; 1243 } 1244 } 1245 1246 copy_metadata(clone, buffer); 1247 1248 CREATE_PARANOIA_CHECK_SET(clone, "net_buffer"); 1249 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, clone, &clone->size, 1250 sizeof(clone->size)); 1251 CHECK_BUFFER(buffer); 1252 CHECK_BUFFER(clone); 1253 1254 T(Clone(buffer, shareFreeSpace, clone)); 1255 1256 return clone; 1257 #endif 1258 } 1259 1260 1261 /*! Split the buffer at offset, the header data 1262 is returned as new buffer. 1263 */ 1264 static net_buffer* 1265 split_buffer(net_buffer* from, uint32 offset) 1266 { 1267 net_buffer* buffer = create_buffer(DATA_NODE_SIZE); 1268 if (buffer == NULL) 1269 return NULL; 1270 1271 copy_metadata(buffer, from); 1272 1273 ParanoiaChecker _(from); 1274 ParanoiaChecker _2(buffer); 1275 1276 TRACE(("%ld: split_buffer(buffer %p -> %p, offset %ld)\n", 1277 find_thread(NULL), from, buffer, offset)); 1278 1279 if (append_data_from_buffer(buffer, from, offset) == B_OK) { 1280 if (remove_header(from, offset) == B_OK) { 1281 CHECK_BUFFER(from); 1282 CHECK_BUFFER(buffer); 1283 T(Split(from, offset, buffer)); 1284 return buffer; 1285 } 1286 } 1287 1288 free_buffer(buffer); 1289 CHECK_BUFFER(from); 1290 return NULL; 1291 } 1292 1293 1294 /*! Merges the second buffer with the first. If \a after is \c true, the 1295 second buffer's contents will be appended to the first ones, else they 1296 will be prepended. 1297 The second buffer will be freed if this function succeeds. 1298 */ 1299 static status_t 1300 merge_buffer(net_buffer* _buffer, net_buffer* _with, bool after) 1301 { 1302 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1303 net_buffer_private* with = (net_buffer_private*)_with; 1304 if (with == NULL) 1305 return B_BAD_VALUE; 1306 1307 TRACE(("%ld: merge buffer %p with %p (%s)\n", find_thread(NULL), buffer, 1308 with, after ? "after" : "before")); 1309 T(Merge(buffer, with, after)); 1310 //dump_buffer(buffer); 1311 //dprintf("with:\n"); 1312 //dump_buffer(with); 1313 1314 ParanoiaChecker _(buffer); 1315 CHECK_BUFFER(buffer); 1316 CHECK_BUFFER(with); 1317 1318 // TODO: this is currently very simplistic, I really need to finish the 1319 // harder part of this implementation (data_node management per header) 1320 1321 data_node* before = NULL; 1322 1323 // TODO: Do allocating nodes (the only part that can fail) upfront. Put them 1324 // in a list, so we can easily clean up, if necessary. 1325 1326 if (!after) { 1327 // change offset of all nodes already in the buffer 1328 data_node* node = NULL; 1329 while (true) { 1330 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1331 if (node == NULL) 1332 break; 1333 1334 node->offset += with->size; 1335 if (before == NULL) 1336 before = node; 1337 } 1338 } 1339 1340 data_node* last = NULL; 1341 1342 while (true) { 1343 data_node* node = (data_node*)list_get_next_item(&with->buffers, last); 1344 if (node == NULL) 1345 break; 1346 1347 if ((uint8*)node > (uint8*)node->header 1348 && (uint8*)node < (uint8*)node->header + BUFFER_SIZE) { 1349 // The node is already in the buffer, we can just move it 1350 // over to the new owner 1351 list_remove_item(&with->buffers, node); 1352 } else { 1353 // we need a new place for this node 1354 data_node* newNode = add_data_node(buffer, node->header); 1355 if (newNode == NULL) { 1356 // TODO: try to revert buffers to their initial state!! 1357 return ENOBUFS; 1358 } 1359 1360 last = node; 1361 *newNode = *node; 1362 node = newNode; 1363 // the old node will get freed with its buffer 1364 } 1365 1366 if (after) { 1367 list_add_item(&buffer->buffers, node); 1368 node->offset = buffer->size; 1369 } else 1370 list_insert_item_before(&buffer->buffers, before, node); 1371 1372 buffer->size += node->used; 1373 } 1374 1375 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1376 sizeof(buffer->size)); 1377 1378 // the data has been merged completely at this point 1379 free_buffer(with); 1380 1381 //dprintf(" merge result:\n"); 1382 //dump_buffer(buffer); 1383 CHECK_BUFFER(buffer); 1384 1385 return B_OK; 1386 } 1387 1388 1389 /*! Writes into existing allocated memory. 1390 \return B_BAD_VALUE if you write outside of the buffers current 1391 bounds. 1392 */ 1393 static status_t 1394 write_data(net_buffer* _buffer, size_t offset, const void* data, size_t size) 1395 { 1396 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1397 1398 T(Write(buffer, offset, data, size)); 1399 1400 ParanoiaChecker _(buffer); 1401 1402 if (offset + size > buffer->size) 1403 return B_BAD_VALUE; 1404 if (size == 0) 1405 return B_OK; 1406 1407 // find first node to write into 1408 data_node* node = get_node_at_offset(buffer, offset); 1409 if (node == NULL) 1410 return B_BAD_VALUE; 1411 1412 offset -= node->offset; 1413 1414 while (true) { 1415 size_t written = min_c(size, node->used - offset); 1416 memcpy(node->start + offset, data, written); 1417 1418 size -= written; 1419 if (size == 0) 1420 break; 1421 1422 offset = 0; 1423 data = (void*)((uint8*)data + written); 1424 1425 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1426 if (node == NULL) 1427 return B_BAD_VALUE; 1428 } 1429 1430 CHECK_BUFFER(buffer); 1431 1432 return B_OK; 1433 } 1434 1435 1436 static status_t 1437 read_data(net_buffer* _buffer, size_t offset, void* data, size_t size) 1438 { 1439 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1440 1441 T(Read(buffer, offset, data, size)); 1442 1443 ParanoiaChecker _(buffer); 1444 1445 if (offset + size > buffer->size) 1446 return B_BAD_VALUE; 1447 if (size == 0) 1448 return B_OK; 1449 1450 // find first node to read from 1451 data_node* node = get_node_at_offset(buffer, offset); 1452 if (node == NULL) 1453 return B_BAD_VALUE; 1454 1455 offset -= node->offset; 1456 1457 while (true) { 1458 size_t bytesRead = min_c(size, node->used - offset); 1459 memcpy(data, node->start + offset, bytesRead); 1460 1461 size -= bytesRead; 1462 if (size == 0) 1463 break; 1464 1465 offset = 0; 1466 data = (void*)((uint8*)data + bytesRead); 1467 1468 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1469 if (node == NULL) 1470 return B_BAD_VALUE; 1471 } 1472 1473 CHECK_BUFFER(buffer); 1474 1475 return B_OK; 1476 } 1477 1478 1479 static status_t 1480 prepend_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer) 1481 { 1482 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1483 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 1484 1485 T(PrependSize(buffer, size)); 1486 1487 ParanoiaChecker _(buffer); 1488 1489 TRACE(("%ld: prepend_size(buffer %p, size %ld) [has %u]\n", 1490 find_thread(NULL), buffer, size, node->HeaderSpace())); 1491 //dump_buffer(buffer); 1492 1493 if (node->HeaderSpace() < size) { 1494 // we need to prepend new buffers 1495 1496 size_t bytesLeft = size; 1497 size_t sizePrepended = 0; 1498 do { 1499 if (node->HeaderSpace() == 0) { 1500 size_t headerSpace = MAX_FREE_BUFFER_SIZE; 1501 data_header* header = create_data_header(headerSpace); 1502 if (header == NULL) { 1503 remove_header(buffer, sizePrepended); 1504 return B_NO_MEMORY; 1505 } 1506 1507 data_node* previous = node; 1508 1509 node = (data_node*)add_first_data_node(header); 1510 1511 list_insert_item_before(&buffer->buffers, previous, node); 1512 1513 // Release the initial reference to the header, so that it will 1514 // be deleted when the node is removed. 1515 release_data_header(header); 1516 } 1517 1518 size_t willConsume = min_c(bytesLeft, node->HeaderSpace()); 1519 1520 node->SubtractHeaderSpace(willConsume); 1521 node->start -= willConsume; 1522 node->used += willConsume; 1523 bytesLeft -= willConsume; 1524 sizePrepended += willConsume; 1525 } while (bytesLeft > 0); 1526 1527 // correct data offset in all nodes 1528 1529 size_t offset = 0; 1530 node = NULL; 1531 while ((node = (data_node*)list_get_next_item(&buffer->buffers, 1532 node)) != NULL) { 1533 node->offset = offset; 1534 offset += node->used; 1535 } 1536 1537 if (_contiguousBuffer) 1538 *_contiguousBuffer = NULL; 1539 } else { 1540 // the data fits into this buffer 1541 node->SubtractHeaderSpace(size); 1542 node->start -= size; 1543 node->used += size; 1544 1545 if (_contiguousBuffer) 1546 *_contiguousBuffer = node->start; 1547 1548 // adjust offset of following nodes 1549 while ((node = (data_node*)list_get_next_item(&buffer->buffers, node)) 1550 != NULL) { 1551 node->offset += size; 1552 } 1553 } 1554 1555 buffer->size += size; 1556 1557 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1558 sizeof(buffer->size)); 1559 1560 //dprintf(" prepend_size result:\n"); 1561 //dump_buffer(buffer); 1562 CHECK_BUFFER(buffer); 1563 return B_OK; 1564 } 1565 1566 1567 static status_t 1568 prepend_data(net_buffer* buffer, const void* data, size_t size) 1569 { 1570 void* contiguousBuffer; 1571 status_t status = prepend_size(buffer, size, &contiguousBuffer); 1572 if (status < B_OK) 1573 return status; 1574 1575 if (contiguousBuffer) 1576 memcpy(contiguousBuffer, data, size); 1577 else 1578 write_data(buffer, 0, data, size); 1579 1580 //dprintf(" prepend result:\n"); 1581 //dump_buffer(buffer); 1582 1583 return B_OK; 1584 } 1585 1586 1587 static status_t 1588 append_size(net_buffer* _buffer, size_t size, void** _contiguousBuffer) 1589 { 1590 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1591 data_node* node = (data_node*)list_get_last_item(&buffer->buffers); 1592 1593 T(AppendSize(buffer, size)); 1594 1595 ParanoiaChecker _(buffer); 1596 1597 TRACE(("%ld: append_size(buffer %p, size %ld)\n", find_thread(NULL), 1598 buffer, size)); 1599 //dump_buffer(buffer); 1600 1601 if (node->TailSpace() < size) { 1602 // we need to append at least one new buffer 1603 uint32 previousTailSpace = node->TailSpace(); 1604 uint32 headerSpace = DATA_NODE_SIZE; 1605 uint32 sizeUsed = MAX_FREE_BUFFER_SIZE - headerSpace; 1606 1607 // allocate space left in the node 1608 node->SetTailSpace(0); 1609 node->used += previousTailSpace; 1610 buffer->size += previousTailSpace; 1611 uint32 sizeAdded = previousTailSpace; 1612 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1613 sizeof(buffer->size)); 1614 1615 // allocate all buffers 1616 1617 while (sizeAdded < size) { 1618 if (sizeAdded + sizeUsed > size) { 1619 // last data_header and not all available space is used 1620 sizeUsed = size - sizeAdded; 1621 } 1622 1623 data_header* header = create_data_header(headerSpace); 1624 if (header == NULL) { 1625 remove_trailer(buffer, sizeAdded); 1626 return B_NO_MEMORY; 1627 } 1628 1629 node = add_first_data_node(header); 1630 1631 node->SetTailSpace(node->TailSpace() - sizeUsed); 1632 node->used = sizeUsed; 1633 node->offset = buffer->size; 1634 1635 buffer->size += sizeUsed; 1636 sizeAdded += sizeUsed; 1637 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1638 sizeof(buffer->size)); 1639 1640 list_add_item(&buffer->buffers, node); 1641 1642 // Release the initial reference to the header, so that it will 1643 // be deleted when the node is removed. 1644 release_data_header(header); 1645 } 1646 1647 if (_contiguousBuffer) 1648 *_contiguousBuffer = NULL; 1649 1650 //dprintf(" append result 1:\n"); 1651 //dump_buffer(buffer); 1652 CHECK_BUFFER(buffer); 1653 1654 return B_OK; 1655 } 1656 1657 // the data fits into this buffer 1658 node->SetTailSpace(node->TailSpace() - size); 1659 1660 if (_contiguousBuffer) 1661 *_contiguousBuffer = node->start + node->used; 1662 1663 node->used += size; 1664 buffer->size += size; 1665 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1666 sizeof(buffer->size)); 1667 1668 //dprintf(" append result 2:\n"); 1669 //dump_buffer(buffer); 1670 CHECK_BUFFER(buffer); 1671 1672 return B_OK; 1673 } 1674 1675 1676 static status_t 1677 append_data(net_buffer* buffer, const void* data, size_t size) 1678 { 1679 size_t used = buffer->size; 1680 1681 void* contiguousBuffer; 1682 status_t status = append_size(buffer, size, &contiguousBuffer); 1683 if (status < B_OK) 1684 return status; 1685 1686 if (contiguousBuffer) 1687 memcpy(contiguousBuffer, data, size); 1688 else 1689 write_data(buffer, used, data, size); 1690 1691 return B_OK; 1692 } 1693 1694 1695 /*! Removes bytes from the beginning of the buffer. 1696 */ 1697 static status_t 1698 remove_header(net_buffer* _buffer, size_t bytes) 1699 { 1700 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1701 1702 T(RemoveHeader(buffer, bytes)); 1703 1704 ParanoiaChecker _(buffer); 1705 1706 if (bytes > buffer->size) 1707 return B_BAD_VALUE; 1708 1709 TRACE(("%ld: remove_header(buffer %p, %ld bytes)\n", find_thread(NULL), 1710 buffer, bytes)); 1711 //dump_buffer(buffer); 1712 1713 size_t left = bytes; 1714 data_node* node = NULL; 1715 1716 while (left >= 0) { 1717 node = (data_node*)list_get_first_item(&buffer->buffers); 1718 if (node == NULL) { 1719 if (left == 0) 1720 break; 1721 CHECK_BUFFER(buffer); 1722 return B_ERROR; 1723 } 1724 1725 if (node->used > left) 1726 break; 1727 1728 // node will be removed completely 1729 list_remove_item(&buffer->buffers, node); 1730 left -= node->used; 1731 remove_data_node(node); 1732 node = NULL; 1733 } 1734 1735 // cut remaining node, if any 1736 1737 if (node != NULL) { 1738 size_t cut = min_c(node->used, left); 1739 node->offset = 0; 1740 node->start += cut; 1741 node->AddHeaderSpace(cut); 1742 node->used -= cut; 1743 1744 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1745 } 1746 1747 // adjust offset of following nodes 1748 while (node != NULL) { 1749 node->offset -= bytes; 1750 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1751 } 1752 1753 buffer->size -= bytes; 1754 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1755 sizeof(buffer->size)); 1756 1757 //dprintf(" remove result:\n"); 1758 //dump_buffer(buffer); 1759 CHECK_BUFFER(buffer); 1760 1761 return B_OK; 1762 } 1763 1764 1765 /*! Removes bytes from the end of the buffer. 1766 */ 1767 static status_t 1768 remove_trailer(net_buffer* buffer, size_t bytes) 1769 { 1770 return trim_data(buffer, buffer->size - bytes); 1771 } 1772 1773 1774 /*! Trims the buffer to the specified \a newSize by removing space from 1775 the end of the buffer. 1776 */ 1777 static status_t 1778 trim_data(net_buffer* _buffer, size_t newSize) 1779 { 1780 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1781 TRACE(("%ld: trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n", 1782 find_thread(NULL), buffer, newSize, buffer->size)); 1783 T(Trim(buffer, newSize)); 1784 //dump_buffer(buffer); 1785 1786 ParanoiaChecker _(buffer); 1787 1788 if (newSize > buffer->size) 1789 return B_BAD_VALUE; 1790 if (newSize == buffer->size) 1791 return B_OK; 1792 1793 data_node* node = get_node_at_offset(buffer, newSize); 1794 if (node == NULL) { 1795 // trim size greater than buffer size 1796 return B_BAD_VALUE; 1797 } 1798 1799 int32 diff = node->used + node->offset - newSize; 1800 node->SetTailSpace(node->TailSpace() + diff); 1801 node->used -= diff; 1802 1803 if (node->used > 0) 1804 node = (data_node*)list_get_next_item(&buffer->buffers, node); 1805 1806 while (node != NULL) { 1807 data_node* next = (data_node*)list_get_next_item(&buffer->buffers, node); 1808 list_remove_item(&buffer->buffers, node); 1809 remove_data_node(node); 1810 1811 node = next; 1812 } 1813 1814 buffer->size = newSize; 1815 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1816 sizeof(buffer->size)); 1817 1818 //dprintf(" trim result:\n"); 1819 //dump_buffer(buffer); 1820 CHECK_BUFFER(buffer); 1821 1822 return B_OK; 1823 } 1824 1825 1826 /*! Appends data coming from buffer \a source to the buffer \a buffer. It only 1827 clones the data, though, that is the data is not copied, just referenced. 1828 */ 1829 static status_t 1830 append_cloned_data(net_buffer* _buffer, net_buffer* _source, uint32 offset, 1831 size_t bytes) 1832 { 1833 if (bytes == 0) 1834 return B_OK; 1835 1836 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1837 net_buffer_private* source = (net_buffer_private*)_source; 1838 TRACE(("%ld: append_cloned_data(buffer %p, source %p, offset = %ld, " 1839 "bytes = %ld)\n", find_thread(NULL), buffer, source, offset, bytes)); 1840 T(AppendCloned(buffer, source, offset, bytes)); 1841 1842 ParanoiaChecker _(buffer); 1843 ParanoiaChecker _2(source); 1844 1845 if (source->size < offset + bytes || source->size < offset) 1846 return B_BAD_VALUE; 1847 1848 // find data_node to start with from the source buffer 1849 data_node* node = get_node_at_offset(source, offset); 1850 if (node == NULL) { 1851 // trim size greater than buffer size 1852 return B_BAD_VALUE; 1853 } 1854 1855 size_t sizeAppended = 0; 1856 1857 while (node != NULL && bytes > 0) { 1858 data_node* clone = add_data_node(buffer, node->header); 1859 if (clone == NULL) { 1860 remove_trailer(buffer, sizeAppended); 1861 return ENOBUFS; 1862 } 1863 1864 if (offset) 1865 offset -= node->offset; 1866 1867 clone->offset = buffer->size; 1868 clone->start = node->start + offset; 1869 clone->used = min_c(bytes, node->used - offset); 1870 clone->flags |= DATA_NODE_READ_ONLY; 1871 1872 list_add_item(&buffer->buffers, clone); 1873 1874 offset = 0; 1875 bytes -= clone->used; 1876 buffer->size += clone->used; 1877 sizeAppended += clone->used; 1878 node = (data_node*)list_get_next_item(&source->buffers, node); 1879 } 1880 1881 if (bytes != 0) 1882 panic("add_cloned_data() failed, bytes != 0!\n"); 1883 1884 //dprintf(" append cloned result:\n"); 1885 //dump_buffer(buffer); 1886 CHECK_BUFFER(source); 1887 CHECK_BUFFER(buffer); 1888 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1889 sizeof(buffer->size)); 1890 1891 return B_OK; 1892 } 1893 1894 1895 void 1896 set_ancillary_data(net_buffer* buffer, ancillary_data_container* container) 1897 { 1898 ((net_buffer_private*)buffer)->ancillary_data = container; 1899 } 1900 1901 1902 ancillary_data_container* 1903 get_ancillary_data(net_buffer* buffer) 1904 { 1905 return ((net_buffer_private*)buffer)->ancillary_data; 1906 } 1907 1908 1909 /*! Moves all ancillary data from buffer \c from to the end of the list of 1910 ancillary data of buffer \c to. Note, that this is the only function that 1911 transfers or copies ancillary data from one buffer to another. 1912 1913 \param from The buffer from which to remove the ancillary data. 1914 \param to The buffer to which to add the ancillary data. 1915 \return A pointer to the first of the moved ancillary data, if any, \c NULL 1916 otherwise. 1917 */ 1918 static void* 1919 transfer_ancillary_data(net_buffer* _from, net_buffer* _to) 1920 { 1921 net_buffer_private* from = (net_buffer_private*)_from; 1922 net_buffer_private* to = (net_buffer_private*)_to; 1923 1924 if (from == NULL || to == NULL) 1925 return NULL; 1926 1927 if (from->ancillary_data == NULL) 1928 return NULL; 1929 1930 if (to->ancillary_data == NULL) { 1931 // no ancillary data in the target buffer 1932 to->ancillary_data = from->ancillary_data; 1933 from->ancillary_data = NULL; 1934 return next_ancillary_data(to->ancillary_data, NULL, NULL); 1935 } 1936 1937 // both have ancillary data 1938 void* data = move_ancillary_data(from->ancillary_data, 1939 to->ancillary_data); 1940 delete_ancillary_data_container(from->ancillary_data); 1941 from->ancillary_data = NULL; 1942 1943 return data; 1944 } 1945 1946 1947 /*! Tries to directly access the requested space in the buffer. 1948 If the space is contiguous, the function will succeed and place a pointer 1949 to that space into \a _contiguousBuffer. 1950 1951 \return B_BAD_VALUE if the offset is outside of the buffer's bounds. 1952 \return B_ERROR in case the buffer is not contiguous at that location. 1953 */ 1954 static status_t 1955 direct_access(net_buffer* _buffer, uint32 offset, size_t size, 1956 void** _contiguousBuffer) 1957 { 1958 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1959 1960 ParanoiaChecker _(buffer); 1961 1962 //TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, 1963 // size)); 1964 1965 if (offset + size > buffer->size) 1966 return B_BAD_VALUE; 1967 1968 // find node to access 1969 data_node* node = get_node_at_offset(buffer, offset); 1970 if (node == NULL) 1971 return B_BAD_VALUE; 1972 1973 offset -= node->offset; 1974 1975 if (size > node->used - offset) 1976 return B_ERROR; 1977 1978 *_contiguousBuffer = node->start + offset; 1979 return B_OK; 1980 } 1981 1982 1983 static int32 1984 checksum_data(net_buffer* _buffer, uint32 offset, size_t size, bool finalize) 1985 { 1986 net_buffer_private* buffer = (net_buffer_private*)_buffer; 1987 1988 if (offset + size > buffer->size || size == 0) 1989 return B_BAD_VALUE; 1990 1991 // find first node to read from 1992 data_node* node = get_node_at_offset(buffer, offset); 1993 if (node == NULL) 1994 return B_ERROR; 1995 1996 offset -= node->offset; 1997 1998 // Since the maximum buffer size is 65536 bytes, it's impossible 1999 // to overlap 32 bit - we don't need to handle this overlap in 2000 // the loop, we can safely do it afterwards 2001 uint32 sum = 0; 2002 2003 while (true) { 2004 size_t bytes = min_c(size, node->used - offset); 2005 if ((offset + node->offset) & 1) { 2006 // if we're at an uneven offset, we have to swap the checksum 2007 sum += __swap_int16(compute_checksum(node->start + offset, bytes)); 2008 } else 2009 sum += compute_checksum(node->start + offset, bytes); 2010 2011 size -= bytes; 2012 if (size == 0) 2013 break; 2014 2015 offset = 0; 2016 2017 node = (data_node*)list_get_next_item(&buffer->buffers, node); 2018 if (node == NULL) 2019 return B_ERROR; 2020 } 2021 2022 while (sum >> 16) { 2023 sum = (sum & 0xffff) + (sum >> 16); 2024 } 2025 2026 if (!finalize) 2027 return (uint16)sum; 2028 2029 return (uint16)~sum; 2030 } 2031 2032 2033 static uint32 2034 get_iovecs(net_buffer* _buffer, struct iovec* iovecs, uint32 vecCount) 2035 { 2036 net_buffer_private* buffer = (net_buffer_private*)_buffer; 2037 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 2038 uint32 count = 0; 2039 2040 while (node != NULL && count < vecCount) { 2041 if (node->used > 0) { 2042 iovecs[count].iov_base = node->start; 2043 iovecs[count].iov_len = node->used; 2044 count++; 2045 } 2046 2047 node = (data_node*)list_get_next_item(&buffer->buffers, node); 2048 } 2049 2050 return count; 2051 } 2052 2053 2054 static uint32 2055 count_iovecs(net_buffer* _buffer) 2056 { 2057 net_buffer_private* buffer = (net_buffer_private*)_buffer; 2058 data_node* node = (data_node*)list_get_first_item(&buffer->buffers); 2059 uint32 count = 0; 2060 2061 while (node != NULL) { 2062 if (node->used > 0) 2063 count++; 2064 2065 node = (data_node*)list_get_next_item(&buffer->buffers, node); 2066 } 2067 2068 return count; 2069 } 2070 2071 2072 static void 2073 swap_addresses(net_buffer* buffer) 2074 { 2075 std::swap(buffer->source, buffer->destination); 2076 } 2077 2078 2079 static status_t 2080 std_ops(int32 op, ...) 2081 { 2082 switch (op) { 2083 case B_MODULE_INIT: 2084 // TODO: improve our code a bit so we can add constructors 2085 // and keep around half-constructed buffers in the slab 2086 2087 sNetBufferCache = create_object_cache("net buffer cache", 2088 sizeof(net_buffer_private), 8, NULL, NULL, NULL); 2089 if (sNetBufferCache == NULL) 2090 return B_NO_MEMORY; 2091 2092 sDataNodeCache = create_object_cache("data node cache", BUFFER_SIZE, 2093 0, NULL, NULL, NULL); 2094 if (sDataNodeCache == NULL) { 2095 delete_object_cache(sNetBufferCache); 2096 return B_NO_MEMORY; 2097 } 2098 2099 #if ENABLE_DEBUGGER_COMMANDS 2100 add_debugger_command_etc("net_buffer_stats", &dump_net_buffer_stats, 2101 "Print net buffer statistics", 2102 "\nPrint net buffer statistics.\n", 0); 2103 #endif 2104 2105 return B_OK; 2106 2107 case B_MODULE_UNINIT: 2108 #if ENABLE_DEBUGGER_COMMANDS 2109 remove_debugger_command("net_buffer_stats", &dump_net_buffer_stats); 2110 #endif 2111 delete_object_cache(sNetBufferCache); 2112 delete_object_cache(sDataNodeCache); 2113 return B_OK; 2114 2115 default: 2116 return B_ERROR; 2117 } 2118 } 2119 2120 2121 net_buffer_module_info gNetBufferModule = { 2122 { 2123 NET_BUFFER_MODULE_NAME, 2124 0, 2125 std_ops 2126 }, 2127 create_buffer, 2128 free_buffer, 2129 2130 duplicate_buffer, 2131 clone_buffer, 2132 split_buffer, 2133 merge_buffer, 2134 2135 prepend_size, 2136 prepend_data, 2137 append_size, 2138 append_data, 2139 NULL, // insert 2140 NULL, // remove 2141 remove_header, 2142 remove_trailer, 2143 trim_data, 2144 append_cloned_data, 2145 2146 NULL, // associate_data 2147 2148 set_ancillary_data, 2149 get_ancillary_data, 2150 transfer_ancillary_data, 2151 2152 direct_access, 2153 read_data, 2154 write_data, 2155 2156 checksum_data, 2157 2158 NULL, // get_memory_map 2159 get_iovecs, 2160 count_iovecs, 2161 2162 swap_addresses, 2163 2164 dump_buffer, // dump 2165 }; 2166 2167