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