1 /* 2 * Copyright 2006-2008, 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; // the current place where we 129 // 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)) != NULL) { 582 dprintf(" node %p, offset %lu, used %u, header %u, tail %u, header %p\n", 583 node, node->offset, node->used, node->HeaderSpace(), node->TailSpace(), node->header); 584 //dump_block((char *)node->start, node->used, " "); 585 dump_block((char *)node->start, min_c(node->used, 32), " "); 586 } 587 } 588 #endif 589 590 591 #if ENABLE_DEBUGGER_COMMANDS 592 593 static int 594 dump_net_buffer_stats(int argc, char** argv) 595 { 596 kprintf("allocated data headers: %7ld / %7ld\n", sAllocatedDataHeaderCount, 597 sEverAllocatedDataHeaderCount); 598 kprintf("allocated net buffers: %7ld / %7ld\n", sAllocatedNetBufferCount, 599 sEverAllocatedNetBufferCount); 600 return 0; 601 } 602 603 #endif // ENABLE_DEBUGGER_COMMANDS 604 605 606 #if PARANOID_BUFFER_CHECK 607 608 static void 609 check_buffer(net_buffer *_buffer) 610 { 611 net_buffer_private *buffer = (net_buffer_private*)_buffer; 612 613 // sum up the size of all nodes 614 size_t size = 0; 615 616 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 617 while (node != NULL) { 618 if (node->offset != size) { 619 panic("net_buffer %p: bad node %p offset (%lu vs. %lu)", 620 buffer, node, node->offset, size); 621 return; 622 } 623 size += node->used; 624 node = (data_node *)list_get_next_item(&buffer->buffers, node); 625 } 626 627 if (size != buffer->size) { 628 panic("net_buffer %p size != sum of its data node sizes (%lu vs. %lu)", 629 buffer, buffer->size, size); 630 return; 631 } 632 } 633 634 635 #if 0 636 static void 637 check_buffer_contents(net_buffer *buffer, size_t offset, const void* data, 638 size_t size) 639 { 640 void* bufferData = malloc(size); 641 if (bufferData == NULL) 642 return; 643 644 if (read_data(buffer, offset, bufferData, size) == B_OK) { 645 if (memcmp(bufferData, data, size) != 0) { 646 int32 index = 0; 647 while (((uint8*)data)[index] == ((uint8*)bufferData)[index]) 648 index++; 649 panic("check_buffer_contents(): contents check failed at index " 650 "%ld, buffer: %p, offset: %lu, size: %lu", index, buffer, 651 offset, size); 652 } 653 } else { 654 panic("failed to read from buffer %p, offset: %lu, size: %lu", 655 buffer, offset, size); 656 } 657 658 free(bufferData); 659 } 660 661 662 static void 663 check_buffer_contents(net_buffer *buffer, size_t offset, net_buffer *source, 664 size_t sourceOffset, size_t size) 665 { 666 void* bufferData = malloc(size); 667 if (bufferData == NULL) 668 return; 669 670 if (read_data(source, sourceOffset, bufferData, size) == B_OK) { 671 check_buffer_contents(buffer, offset, bufferData, size); 672 } else { 673 panic("failed to read from source buffer %p, offset: %lu, size: %lu", 674 source, sourceOffset, size); 675 } 676 677 free(bufferData); 678 } 679 #endif 680 681 682 # define CHECK_BUFFER(buffer) check_buffer(buffer) 683 #else 684 # define CHECK_BUFFER(buffer) do {} while (false) 685 #endif // !PARANOID_BUFFER_CHECK 686 687 688 static inline data_header * 689 allocate_data_header() 690 { 691 #if ENABLE_DEBUGGER_COMMANDS 692 atomic_add(&sAllocatedDataHeaderCount, 1); 693 atomic_add(&sEverAllocatedDataHeaderCount, 1); 694 #endif 695 return (data_header *)object_cache_alloc(sDataNodeCache, CACHE_DONT_SLEEP); 696 } 697 698 699 static inline net_buffer_private * 700 allocate_net_buffer() 701 { 702 #if ENABLE_DEBUGGER_COMMANDS 703 atomic_add(&sAllocatedNetBufferCount, 1); 704 atomic_add(&sEverAllocatedNetBufferCount, 1); 705 #endif 706 return (net_buffer_private *)object_cache_alloc(sNetBufferCache, 707 CACHE_DONT_SLEEP); 708 } 709 710 711 static inline void 712 free_data_header(data_header *header) 713 { 714 #if ENABLE_DEBUGGER_COMMANDS 715 if (header != NULL) 716 atomic_add(&sAllocatedDataHeaderCount, -1); 717 #endif 718 object_cache_free(sDataNodeCache, header); 719 } 720 721 722 static inline void 723 free_net_buffer(net_buffer_private *buffer) 724 { 725 #if ENABLE_DEBUGGER_COMMANDS 726 if (buffer != NULL) 727 atomic_add(&sAllocatedNetBufferCount, -1); 728 #endif 729 object_cache_free(sNetBufferCache, buffer); 730 } 731 732 733 static data_header * 734 create_data_header(size_t headerSpace) 735 { 736 data_header *header = allocate_data_header(); 737 if (header == NULL) 738 return NULL; 739 740 header->ref_count = 1; 741 header->physical_address = 0; 742 // TODO: initialize this correctly 743 header->space.size = headerSpace; 744 header->space.free = headerSpace; 745 header->data_end = (uint8 *)header + DATA_HEADER_SIZE; 746 header->tail_space = (uint8 *)header + BUFFER_SIZE - header->data_end 747 - headerSpace; 748 header->first_free = NULL; 749 750 TRACE(("%ld: create new data header %p\n", find_thread(NULL), header)); 751 T2(CreateDataHeader(header)); 752 return header; 753 } 754 755 756 static void 757 release_data_header(data_header *header) 758 { 759 int32 refCount = atomic_add(&header->ref_count, -1); 760 T2(ReleaseDataHeader(header, refCount - 1)); 761 if (refCount != 1) 762 return; 763 764 TRACE(("%ld: free header %p\n", find_thread(NULL), header)); 765 free_data_header(header); 766 } 767 768 769 inline void 770 acquire_data_header(data_header *header) 771 { 772 int32 refCount = atomic_add(&header->ref_count, 1); 773 (void)refCount; 774 T2(AcquireDataHeader(header, refCount + 1)); 775 } 776 777 778 static void 779 free_data_header_space(data_header *header, uint8 *data, size_t size) 780 { 781 if (size < sizeof(free_data)) 782 size = sizeof(free_data); 783 784 free_data *freeData = (free_data *)data; 785 freeData->next = header->first_free; 786 freeData->size = size; 787 788 header->first_free = freeData; 789 } 790 791 792 /*! 793 Tries to allocate \a size bytes from the free space in the header. 794 */ 795 static uint8 * 796 alloc_data_header_space(data_header *header, size_t size) 797 { 798 if (size < sizeof(free_data)) 799 size = sizeof(free_data); 800 size = _ALIGN(size); 801 802 if (header->first_free != NULL && header->first_free->size >= size) { 803 // the first entry of the header space matches the allocation's needs 804 // TODO: If the free space is greater than what shall be allocated, we leak 805 // the remainder of the space. We should only allocate multiples of 806 // _ALIGN(sizeof(free_data)) and split free space in this case. It's not that 807 // pressing, since the only thing allocated ATM are data_nodes, and thus the 808 // free space entries will always have the right size. 809 uint8 *data = (uint8 *)header->first_free; 810 header->first_free = header->first_free->next; 811 return data; 812 } 813 814 if (header->space.free < size) { 815 // there is no free space left, search free list 816 free_data *freeData = header->first_free; 817 free_data *last = NULL; 818 while (freeData != NULL) { 819 if (last != NULL && freeData->size >= size) { 820 // take this one 821 last->next = freeData->next; 822 return (uint8 *)freeData; 823 } 824 825 last = freeData; 826 freeData = freeData->next; 827 } 828 829 return NULL; 830 } 831 832 // allocate new space 833 834 uint8 *data = header->data_end; 835 header->data_end += size; 836 header->space.free -= size; 837 838 return data; 839 } 840 841 842 static uint8 * 843 alloc_data_header_space(net_buffer_private *buffer, size_t size, 844 data_header **_header = NULL) 845 { 846 // try to allocate in our current allocation header 847 uint8 *allocated = alloc_data_header_space(buffer->allocation_header, size); 848 if (allocated == NULL) { 849 // not enough header space left -- create a fresh buffer for headers 850 data_header *header = create_data_header(MAX_FREE_BUFFER_SIZE); 851 if (header == NULL) 852 return NULL; 853 854 // release our reference to the old header -- it will will stay around 855 // until the last reference to it is released 856 release_data_header(buffer->allocation_header); 857 buffer->allocation_header = header; 858 // We keep the initial reference. 859 860 // now the allocation can only fail, if size is too big 861 allocated = alloc_data_header_space(buffer->allocation_header, size); 862 } 863 864 if (_header != NULL) 865 *_header = buffer->allocation_header; 866 867 return allocated; 868 } 869 870 871 static data_node * 872 add_first_data_node(data_header *header) 873 { 874 data_node *node = (data_node *)alloc_data_header_space(header, 875 sizeof(data_node)); 876 if (node == NULL) 877 return NULL; 878 879 TRACE(("%ld: add first data node %p to header %p\n", find_thread(NULL), 880 node, header)); 881 882 acquire_data_header(header); 883 884 memset(node, 0, sizeof(struct data_node)); 885 node->located = header; 886 node->header = header; 887 node->offset = 0; 888 node->start = header->data_end + header->space.free; 889 node->used = 0; 890 node->flags = 0; 891 892 return node; 893 } 894 895 896 static data_node * 897 add_data_node(net_buffer_private *buffer, data_header *header) 898 { 899 data_header *located; 900 data_node *node = (data_node *)alloc_data_header_space(buffer, 901 sizeof(data_node), &located); 902 if (node == NULL) 903 return NULL; 904 905 TRACE(("%ld: add data node %p to header %p\n", find_thread(NULL), node, 906 header)); 907 908 acquire_data_header(header); 909 if (located != header) 910 acquire_data_header(located); 911 912 memset(node, 0, sizeof(struct data_node)); 913 node->located = located; 914 node->header = header; 915 node->flags = 0; 916 return node; 917 } 918 919 920 void 921 remove_data_node(data_node *node) 922 { 923 data_header *located = node->located; 924 925 TRACE(("%ld: remove data node %p from header %p (located %p)\n", 926 find_thread(NULL), node, node->header, located)); 927 928 // Move all used and tail space to the header space, which is useful in case 929 // this is the first node of a buffer (i.e. the header is an allocation 930 // header). 931 node->FreeSpace(); 932 933 if (located != node->header) 934 release_data_header(node->header); 935 936 if (located == NULL) 937 return; 938 939 free_data_header_space(located, (uint8 *)node, sizeof(data_node)); 940 941 release_data_header(located); 942 } 943 944 945 static inline data_node * 946 get_node_at_offset(net_buffer_private *buffer, size_t offset) 947 { 948 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 949 while (node->offset + node->used <= offset) { 950 node = (data_node *)list_get_next_item(&buffer->buffers, node); 951 if (node == NULL) 952 return NULL; 953 } 954 955 return node; 956 } 957 958 959 static void 960 copy_metadata(net_buffer *destination, const net_buffer *source) 961 { 962 memcpy(destination->source, source->source, 963 min_c(source->source->sa_len, sizeof(sockaddr_storage))); 964 memcpy(destination->destination, source->destination, 965 min_c(source->destination->sa_len, sizeof(sockaddr_storage))); 966 967 destination->flags = source->flags; 968 destination->interface = source->interface; 969 destination->offset = source->offset; 970 destination->size = source->size; 971 destination->protocol = source->protocol; 972 destination->type = source->type; 973 } 974 975 976 // #pragma mark - module API 977 978 979 static net_buffer * 980 create_buffer(size_t headerSpace) 981 { 982 net_buffer_private *buffer = allocate_net_buffer(); 983 if (buffer == NULL) 984 return NULL; 985 986 TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer)); 987 988 // Make sure headerSpace is valid and at least the initial node fits. 989 headerSpace = _ALIGN(headerSpace); 990 if (headerSpace < DATA_NODE_SIZE) 991 headerSpace = DATA_NODE_SIZE; 992 else if (headerSpace > MAX_FREE_BUFFER_SIZE) 993 headerSpace = MAX_FREE_BUFFER_SIZE; 994 995 data_header *header = create_data_header(headerSpace); 996 if (header == NULL) { 997 free_net_buffer(buffer); 998 return NULL; 999 } 1000 buffer->allocation_header = header; 1001 1002 data_node *node = add_first_data_node(header); 1003 1004 list_init(&buffer->buffers); 1005 list_add_item(&buffer->buffers, node); 1006 1007 buffer->ancillary_data = NULL; 1008 1009 buffer->source = (sockaddr *)&buffer->storage.source; 1010 buffer->destination = (sockaddr *)&buffer->storage.destination; 1011 1012 buffer->storage.source.ss_len = 0; 1013 buffer->storage.destination.ss_len = 0; 1014 1015 buffer->interface = NULL; 1016 buffer->offset = 0; 1017 buffer->flags = 0; 1018 buffer->size = 0; 1019 1020 buffer->type = -1; 1021 1022 CHECK_BUFFER(buffer); 1023 CREATE_PARANOIA_CHECK_SET(buffer, "net_buffer"); 1024 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1025 sizeof(buffer->size)); 1026 1027 T(Create(headerSpace, buffer)); 1028 1029 return buffer; 1030 } 1031 1032 1033 static void 1034 free_buffer(net_buffer *_buffer) 1035 { 1036 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1037 1038 TRACE(("%ld: free buffer %p\n", find_thread(NULL), buffer)); 1039 T(Free(buffer)); 1040 1041 CHECK_BUFFER(buffer); 1042 DELETE_PARANOIA_CHECK_SET(buffer); 1043 1044 data_node *node; 1045 while ((node = (data_node *)list_remove_head_item(&buffer->buffers)) != NULL) { 1046 remove_data_node(node); 1047 } 1048 1049 delete_ancillary_data_container(buffer->ancillary_data); 1050 1051 release_data_header(buffer->allocation_header); 1052 1053 free_net_buffer(buffer); 1054 } 1055 1056 1057 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal 1058 storage; they are completely independent from each other. 1059 */ 1060 static net_buffer * 1061 duplicate_buffer(net_buffer *_buffer) 1062 { 1063 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1064 1065 ParanoiaChecker _(buffer); 1066 1067 TRACE(("%ld: duplicate_buffer(buffer %p)\n", find_thread(NULL), buffer)); 1068 1069 // TODO: We might want to choose a better header space. The minimal 1070 // one doesn't allow to prepend any data without allocating a new header. 1071 // The same holds for appending cloned data. 1072 net_buffer *duplicate = create_buffer(DATA_NODE_SIZE); 1073 if (duplicate == NULL) 1074 return NULL; 1075 1076 TRACE(("%ld: duplicate: %p)\n", find_thread(NULL), duplicate)); 1077 1078 // copy the data from the source buffer 1079 1080 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 1081 while (node != NULL) { 1082 if (append_data(duplicate, node->start, node->used) < B_OK) { 1083 free_buffer(duplicate); 1084 CHECK_BUFFER(buffer); 1085 return NULL; 1086 } 1087 1088 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1089 } 1090 1091 copy_metadata(duplicate, buffer); 1092 1093 CHECK_BUFFER(buffer); 1094 CHECK_BUFFER(duplicate); 1095 RUN_PARANOIA_CHECKS(duplicate); 1096 1097 T(Duplicate(buffer, duplicate)); 1098 1099 return duplicate; 1100 } 1101 1102 1103 /*! Clones the buffer by grabbing another reference to the underlying data. 1104 If that data changes, it will be changed in the clone as well. 1105 1106 If \a shareFreeSpace is \c true, the cloned buffer may claim the free 1107 space in the original buffer as the original buffer can still do. If you 1108 are using this, it's your responsibility that only one of the buffers 1109 will do this. 1110 */ 1111 static net_buffer * 1112 clone_buffer(net_buffer *_buffer, bool shareFreeSpace) 1113 { 1114 // TODO: See, if the commented out code can be fixed in a safe way. We could 1115 // probably place cloned nodes on a header not belonging to our buffer, if 1116 // we don't free the header space for the node when removing it. Otherwise we 1117 // mess with the header's free list which might at the same time be accessed 1118 // by another thread. 1119 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1120 1121 net_buffer *clone = create_buffer(MAX_FREE_BUFFER_SIZE); 1122 if (clone == NULL) 1123 return NULL; 1124 1125 if (append_cloned_data(clone, buffer, 0, buffer->size) != B_OK) { 1126 free_buffer(clone); 1127 return NULL; 1128 } 1129 1130 copy_metadata(clone, buffer); 1131 1132 return clone; 1133 1134 #if 0 1135 ParanoiaChecker _(buffer); 1136 1137 TRACE(("%ld: clone_buffer(buffer %p)\n", find_thread(NULL), buffer)); 1138 1139 net_buffer_private *clone = allocate_net_buffer(); 1140 if (clone == NULL) 1141 return NULL; 1142 1143 TRACE(("%ld: clone: %p\n", find_thread(NULL), buffer)); 1144 1145 data_node *sourceNode = (data_node *)list_get_first_item(&buffer->buffers); 1146 if (sourceNode == NULL) { 1147 free_net_buffer(clone); 1148 return NULL; 1149 } 1150 1151 clone->source = (sockaddr *)&clone->storage.source; 1152 clone->destination = (sockaddr *)&clone->storage.destination; 1153 1154 list_init(&clone->buffers); 1155 1156 // grab reference to this buffer - all additional nodes will get 1157 // theirs in add_data_node() 1158 acquire_data_header(sourceNode->header); 1159 data_node *node = &clone->first_node; 1160 node->header = sourceNode->header; 1161 node->located = NULL; 1162 node->used_header_space = &node->own_header_space; 1163 1164 while (sourceNode != NULL) { 1165 node->start = sourceNode->start; 1166 node->used = sourceNode->used; 1167 node->offset = sourceNode->offset; 1168 1169 if (shareFreeSpace) { 1170 // both buffers could claim the free space - note that this option 1171 // has to be used carefully 1172 node->used_header_space = &sourceNode->header->space; 1173 node->tail_space = sourceNode->tail_space; 1174 } else { 1175 // the free space stays with the original buffer 1176 node->used_header_space->size = 0; 1177 node->used_header_space->free = 0; 1178 node->tail_space = 0; 1179 } 1180 1181 // add node to clone's list of buffers 1182 list_add_item(&clone->buffers, node); 1183 1184 sourceNode = (data_node *)list_get_next_item(&buffer->buffers, sourceNode); 1185 if (sourceNode == NULL) 1186 break; 1187 1188 node = add_data_node(sourceNode->header); 1189 if (node == NULL) { 1190 // There was not enough space left for another node in this buffer 1191 // TODO: handle this case! 1192 panic("clone buffer hits size limit... (fix me)"); 1193 free_net_buffer(clone); 1194 return NULL; 1195 } 1196 } 1197 1198 copy_metadata(clone, buffer); 1199 1200 CREATE_PARANOIA_CHECK_SET(clone, "net_buffer"); 1201 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, clone, &clone->size, 1202 sizeof(clone->size)); 1203 CHECK_BUFFER(buffer); 1204 CHECK_BUFFER(clone); 1205 1206 T(Clone(buffer, shareFreeSpace, clone)); 1207 1208 return clone; 1209 #endif 1210 } 1211 1212 1213 /*! 1214 Split the buffer at offset, the header data 1215 is returned as new buffer. 1216 TODO: optimize and avoid making a copy. 1217 */ 1218 static net_buffer * 1219 split_buffer(net_buffer *from, uint32 offset) 1220 { 1221 // TODO: Copying the whole buffer becomes less and less efficient with 1222 // greater size - offset differences. What we actually want is a method 1223 // to copy data from one buffer to another. Then the following should be: 1224 // create buffer, resize, copy data. An additional append_data_from_buffer() 1225 // method would be even better. 1226 net_buffer *buffer = duplicate_buffer(from); 1227 if (buffer == NULL) 1228 return NULL; 1229 1230 ParanoiaChecker _(from); 1231 ParanoiaChecker _2(buffer); 1232 1233 TRACE(("%ld: split_buffer(buffer %p -> %p, offset %ld)\n", 1234 find_thread(NULL), from, buffer, offset)); 1235 1236 if (trim_data(buffer, offset) == B_OK) { 1237 if (remove_header(from, offset) == B_OK) { 1238 CHECK_BUFFER(from); 1239 CHECK_BUFFER(buffer); 1240 T(Split(from, offset, buffer)); 1241 return buffer; 1242 } 1243 } 1244 1245 free_buffer(buffer); 1246 CHECK_BUFFER(from); 1247 return NULL; 1248 } 1249 1250 1251 /*! 1252 Merges the second buffer with the first. If \a after is \c true, the 1253 second buffer's contents will be appended to the first ones, else they 1254 will be prepended. 1255 The second buffer will be freed if this function succeeds. 1256 */ 1257 static status_t 1258 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after) 1259 { 1260 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1261 net_buffer_private *with = (net_buffer_private *)_with; 1262 if (with == NULL) 1263 return B_BAD_VALUE; 1264 1265 TRACE(("%ld: merge buffer %p with %p (%s)\n", find_thread(NULL), buffer, 1266 with, after ? "after" : "before")); 1267 T(Merge(buffer, with, after)); 1268 //dump_buffer(buffer); 1269 //dprintf("with:\n"); 1270 //dump_buffer(with); 1271 1272 ParanoiaChecker _(buffer); 1273 CHECK_BUFFER(buffer); 1274 CHECK_BUFFER(with); 1275 1276 // TODO: this is currently very simplistic, I really need to finish the 1277 // harder part of this implementation (data_node management per header) 1278 1279 data_node *before = NULL; 1280 1281 // TODO: Do allocating nodes (the only part that can fail) upfront. Put them 1282 // in a list, so we can easily clean up, if necessary. 1283 1284 if (!after) { 1285 // change offset of all nodes already in the buffer 1286 data_node *node = NULL; 1287 while (true) { 1288 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1289 if (node == NULL) 1290 break; 1291 1292 node->offset += with->size; 1293 if (before == NULL) 1294 before = node; 1295 } 1296 } 1297 1298 data_node *last = NULL; 1299 1300 while (true) { 1301 data_node *node = (data_node *)list_get_next_item(&with->buffers, last); 1302 if (node == NULL) 1303 break; 1304 1305 if ((uint8 *)node > (uint8 *)node->header 1306 && (uint8 *)node < (uint8 *)node->header + BUFFER_SIZE) { 1307 // The node is already in the buffer, we can just move it 1308 // over to the new owner 1309 list_remove_item(&with->buffers, node); 1310 } else { 1311 // we need a new place for this node 1312 data_node *newNode = add_data_node(buffer, node->header); 1313 if (newNode == NULL) 1314 // TODO: try to revert buffers to their initial state!! 1315 return ENOBUFS; 1316 1317 last = node; 1318 *newNode = *node; 1319 node = newNode; 1320 // the old node will get freed with its buffer 1321 } 1322 1323 if (after) { 1324 list_add_item(&buffer->buffers, node); 1325 node->offset = buffer->size; 1326 } else 1327 list_insert_item_before(&buffer->buffers, before, node); 1328 1329 buffer->size += node->used; 1330 } 1331 1332 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1333 sizeof(buffer->size)); 1334 1335 // the data has been merged completely at this point 1336 free_buffer(with); 1337 1338 //dprintf(" merge result:\n"); 1339 //dump_buffer(buffer); 1340 CHECK_BUFFER(buffer); 1341 1342 return B_OK; 1343 } 1344 1345 1346 /*! Writes into existing allocated memory. 1347 \return B_BAD_VALUE if you write outside of the buffers current 1348 bounds. 1349 */ 1350 static status_t 1351 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size) 1352 { 1353 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1354 1355 T(Write(buffer, offset, data, size)); 1356 1357 ParanoiaChecker _(buffer); 1358 1359 if (offset + size > buffer->size) 1360 return B_BAD_VALUE; 1361 if (size == 0) 1362 return B_OK; 1363 1364 // find first node to write into 1365 data_node *node = get_node_at_offset(buffer, offset); 1366 if (node == NULL) 1367 return B_BAD_VALUE; 1368 1369 offset -= node->offset; 1370 1371 while (true) { 1372 size_t written = min_c(size, node->used - offset); 1373 memcpy(node->start + offset, data, written); 1374 1375 size -= written; 1376 if (size == 0) 1377 break; 1378 1379 offset = 0; 1380 data = (void *)((uint8 *)data + written); 1381 1382 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1383 if (node == NULL) 1384 return B_BAD_VALUE; 1385 } 1386 1387 CHECK_BUFFER(buffer); 1388 1389 return B_OK; 1390 } 1391 1392 1393 static status_t 1394 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size) 1395 { 1396 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1397 1398 T(Read(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 read from 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 bytesRead = min_c(size, node->used - offset); 1416 memcpy(data, node->start + offset, bytesRead); 1417 1418 size -= bytesRead; 1419 if (size == 0) 1420 break; 1421 1422 offset = 0; 1423 data = (void *)((uint8 *)data + bytesRead); 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 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 1438 { 1439 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1440 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 1441 1442 T(PrependSize(buffer, size)); 1443 1444 ParanoiaChecker _(buffer); 1445 1446 TRACE(("%ld: prepend_size(buffer %p, size %ld) [has %u]\n", 1447 find_thread(NULL), buffer, size, node->HeaderSpace())); 1448 //dump_buffer(buffer); 1449 1450 if (node->HeaderSpace() < size) { 1451 // we need to prepend new buffers 1452 1453 size_t bytesLeft = size; 1454 size_t sizePrepended = 0; 1455 do { 1456 if (node->HeaderSpace() == 0) { 1457 size_t headerSpace = MAX_FREE_BUFFER_SIZE; 1458 data_header *header = create_data_header(headerSpace); 1459 if (header == NULL) { 1460 remove_header(buffer, sizePrepended); 1461 return B_NO_MEMORY; 1462 } 1463 1464 data_node *previous = node; 1465 1466 node = (data_node *)add_first_data_node(header); 1467 1468 list_insert_item_before(&buffer->buffers, previous, node); 1469 1470 // Release the initial reference to the header, so that it will 1471 // be deleted when the node is removed. 1472 release_data_header(header); 1473 } 1474 1475 size_t willConsume = min_c(bytesLeft, node->HeaderSpace()); 1476 1477 node->SubtractHeaderSpace(willConsume); 1478 node->start -= willConsume; 1479 node->used += willConsume; 1480 bytesLeft -= willConsume; 1481 sizePrepended += willConsume; 1482 } while (bytesLeft > 0); 1483 1484 // correct data offset in all nodes 1485 1486 size_t offset = 0; 1487 node = NULL; 1488 while ((node = (data_node *)list_get_next_item(&buffer->buffers, 1489 node)) != NULL) { 1490 node->offset = offset; 1491 offset += node->used; 1492 } 1493 1494 if (_contiguousBuffer) 1495 *_contiguousBuffer = NULL; 1496 } else { 1497 // the data fits into this buffer 1498 node->SubtractHeaderSpace(size); 1499 node->start -= size; 1500 node->used += size; 1501 1502 if (_contiguousBuffer) 1503 *_contiguousBuffer = node->start; 1504 1505 // adjust offset of following nodes 1506 while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) { 1507 node->offset += size; 1508 } 1509 } 1510 1511 buffer->size += size; 1512 1513 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1514 sizeof(buffer->size)); 1515 1516 //dprintf(" prepend_size result:\n"); 1517 //dump_buffer(buffer); 1518 CHECK_BUFFER(buffer); 1519 return B_OK; 1520 } 1521 1522 1523 static status_t 1524 prepend_data(net_buffer *buffer, const void *data, size_t size) 1525 { 1526 void *contiguousBuffer; 1527 status_t status = prepend_size(buffer, size, &contiguousBuffer); 1528 if (status < B_OK) 1529 return status; 1530 1531 if (contiguousBuffer) 1532 memcpy(contiguousBuffer, data, size); 1533 else 1534 write_data(buffer, 0, data, size); 1535 1536 //dprintf(" prepend result:\n"); 1537 //dump_buffer(buffer); 1538 1539 return B_OK; 1540 } 1541 1542 1543 static status_t 1544 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 1545 { 1546 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1547 data_node *node = (data_node *)list_get_last_item(&buffer->buffers); 1548 1549 T(AppendSize(buffer, size)); 1550 1551 ParanoiaChecker _(buffer); 1552 1553 TRACE(("%ld: append_size(buffer %p, size %ld)\n", find_thread(NULL), 1554 buffer, size)); 1555 //dump_buffer(buffer); 1556 1557 if (node->TailSpace() < size) { 1558 // we need to append at least one new buffer 1559 uint32 previousTailSpace = node->TailSpace(); 1560 uint32 headerSpace = DATA_NODE_SIZE; 1561 uint32 sizeUsed = MAX_FREE_BUFFER_SIZE - headerSpace; 1562 1563 // allocate space left in the node 1564 node->SetTailSpace(0); 1565 node->used += previousTailSpace; 1566 buffer->size += previousTailSpace; 1567 uint32 sizeAdded = previousTailSpace; 1568 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1569 sizeof(buffer->size)); 1570 1571 // allocate all buffers 1572 1573 while (sizeAdded < size) { 1574 if (sizeAdded + sizeUsed > size) { 1575 // last data_header and not all available space is used 1576 sizeUsed = size - sizeAdded; 1577 } 1578 1579 data_header *header = create_data_header(headerSpace); 1580 if (header == NULL) { 1581 remove_trailer(buffer, sizeAdded); 1582 return B_NO_MEMORY; 1583 } 1584 1585 node = add_first_data_node(header); 1586 1587 node->SetTailSpace(node->TailSpace() - sizeUsed); 1588 node->used = sizeUsed; 1589 node->offset = buffer->size; 1590 1591 buffer->size += sizeUsed; 1592 sizeAdded += sizeUsed; 1593 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1594 sizeof(buffer->size)); 1595 1596 list_add_item(&buffer->buffers, node); 1597 1598 // Release the initial reference to the header, so that it will 1599 // be deleted when the node is removed. 1600 release_data_header(header); 1601 } 1602 1603 if (_contiguousBuffer) 1604 *_contiguousBuffer = NULL; 1605 1606 //dprintf(" append result 1:\n"); 1607 //dump_buffer(buffer); 1608 CHECK_BUFFER(buffer); 1609 1610 return B_OK; 1611 } 1612 1613 // the data fits into this buffer 1614 node->SetTailSpace(node->TailSpace() - size); 1615 1616 if (_contiguousBuffer) 1617 *_contiguousBuffer = node->start + node->used; 1618 1619 node->used += size; 1620 buffer->size += size; 1621 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1622 sizeof(buffer->size)); 1623 1624 //dprintf(" append result 2:\n"); 1625 //dump_buffer(buffer); 1626 CHECK_BUFFER(buffer); 1627 1628 return B_OK; 1629 } 1630 1631 1632 static status_t 1633 append_data(net_buffer *buffer, const void *data, size_t size) 1634 { 1635 size_t used = buffer->size; 1636 1637 void *contiguousBuffer; 1638 status_t status = append_size(buffer, size, &contiguousBuffer); 1639 if (status < B_OK) 1640 return status; 1641 1642 if (contiguousBuffer) 1643 memcpy(contiguousBuffer, data, size); 1644 else 1645 write_data(buffer, used, data, size); 1646 1647 return B_OK; 1648 } 1649 1650 1651 /*! 1652 Removes bytes from the beginning of the buffer. 1653 */ 1654 static status_t 1655 remove_header(net_buffer *_buffer, size_t bytes) 1656 { 1657 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1658 1659 T(RemoveHeader(buffer, bytes)); 1660 1661 ParanoiaChecker _(buffer); 1662 1663 if (bytes > buffer->size) 1664 return B_BAD_VALUE; 1665 1666 TRACE(("%ld: remove_header(buffer %p, %ld bytes)\n", find_thread(NULL), 1667 buffer, bytes)); 1668 //dump_buffer(buffer); 1669 1670 size_t left = bytes; 1671 data_node *node = NULL; 1672 1673 while (left >= 0) { 1674 node = (data_node *)list_get_first_item(&buffer->buffers); 1675 if (node == NULL) { 1676 if (left == 0) 1677 break; 1678 CHECK_BUFFER(buffer); 1679 return B_ERROR; 1680 } 1681 1682 if (node->used > left) 1683 break; 1684 1685 // node will be removed completely 1686 list_remove_item(&buffer->buffers, node); 1687 left -= node->used; 1688 remove_data_node(node); 1689 node = NULL; 1690 } 1691 1692 // cut remaining node, if any 1693 1694 if (node != NULL) { 1695 size_t cut = min_c(node->used, left); 1696 node->offset = 0; 1697 node->start += cut; 1698 node->AddHeaderSpace(cut); 1699 node->used -= cut; 1700 1701 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1702 } 1703 1704 // adjust offset of following nodes 1705 while (node != NULL) { 1706 node->offset -= bytes; 1707 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1708 } 1709 1710 buffer->size -= bytes; 1711 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1712 sizeof(buffer->size)); 1713 1714 //dprintf(" remove result:\n"); 1715 //dump_buffer(buffer); 1716 CHECK_BUFFER(buffer); 1717 1718 return B_OK; 1719 } 1720 1721 1722 /*! 1723 Removes bytes from the end of the buffer. 1724 */ 1725 static status_t 1726 remove_trailer(net_buffer *buffer, size_t bytes) 1727 { 1728 return trim_data(buffer, buffer->size - bytes); 1729 } 1730 1731 1732 /*! 1733 Trims the buffer to the specified \a newSize by removing space from 1734 the end of the buffer. 1735 */ 1736 static status_t 1737 trim_data(net_buffer *_buffer, size_t newSize) 1738 { 1739 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1740 TRACE(("%ld: trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n", 1741 find_thread(NULL), buffer, newSize, buffer->size)); 1742 T(Trim(buffer, newSize)); 1743 //dump_buffer(buffer); 1744 1745 ParanoiaChecker _(buffer); 1746 1747 if (newSize > buffer->size) 1748 return B_BAD_VALUE; 1749 if (newSize == buffer->size) 1750 return B_OK; 1751 1752 data_node *node = get_node_at_offset(buffer, newSize); 1753 if (node == NULL) { 1754 // trim size greater than buffer size 1755 return B_BAD_VALUE; 1756 } 1757 1758 int32 diff = node->used + node->offset - newSize; 1759 node->SetTailSpace(node->TailSpace() + diff); 1760 node->used -= diff; 1761 1762 if (node->used > 0) 1763 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1764 1765 while (node != NULL) { 1766 data_node *next = (data_node *)list_get_next_item(&buffer->buffers, node); 1767 list_remove_item(&buffer->buffers, node); 1768 remove_data_node(node); 1769 1770 node = next; 1771 } 1772 1773 buffer->size = newSize; 1774 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1775 sizeof(buffer->size)); 1776 1777 //dprintf(" trim result:\n"); 1778 //dump_buffer(buffer); 1779 CHECK_BUFFER(buffer); 1780 1781 return B_OK; 1782 } 1783 1784 1785 /*! 1786 Appends data coming from buffer \a source to the buffer \a buffer. It only 1787 clones the data, though, that is the data is not copied, just referenced. 1788 */ 1789 static status_t 1790 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset, 1791 size_t bytes) 1792 { 1793 if (bytes == 0) 1794 return B_OK; 1795 1796 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1797 net_buffer_private *source = (net_buffer_private *)_source; 1798 TRACE(("%ld: append_cloned_data(buffer %p, source %p, offset = %ld, " 1799 "bytes = %ld)\n", find_thread(NULL), buffer, source, offset, bytes)); 1800 T(AppendCloned(buffer, source, offset, bytes)); 1801 1802 ParanoiaChecker _(buffer); 1803 ParanoiaChecker _2(source); 1804 1805 if (source->size < offset + bytes || source->size < offset) 1806 return B_BAD_VALUE; 1807 1808 // find data_node to start with from the source buffer 1809 data_node *node = get_node_at_offset(source, offset); 1810 if (node == NULL) { 1811 // trim size greater than buffer size 1812 return B_BAD_VALUE; 1813 } 1814 1815 size_t sizeAppended = 0; 1816 1817 while (node != NULL && bytes > 0) { 1818 data_node *clone = add_data_node(buffer, node->header); 1819 if (clone == NULL) { 1820 remove_trailer(buffer, sizeAppended); 1821 return ENOBUFS; 1822 } 1823 1824 if (offset) 1825 offset -= node->offset; 1826 1827 clone->offset = buffer->size; 1828 clone->start = node->start + offset; 1829 clone->used = min_c(bytes, node->used - offset); 1830 clone->flags |= DATA_NODE_READ_ONLY; 1831 1832 list_add_item(&buffer->buffers, clone); 1833 1834 offset = 0; 1835 bytes -= clone->used; 1836 buffer->size += clone->used; 1837 sizeAppended += clone->used; 1838 node = (data_node *)list_get_next_item(&source->buffers, node); 1839 } 1840 1841 if (bytes != 0) 1842 panic("add_cloned_data() failed, bytes != 0!\n"); 1843 1844 //dprintf(" append cloned result:\n"); 1845 //dump_buffer(buffer); 1846 CHECK_BUFFER(source); 1847 CHECK_BUFFER(buffer); 1848 SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size, 1849 sizeof(buffer->size)); 1850 1851 return B_OK; 1852 } 1853 1854 1855 void 1856 set_ancillary_data(net_buffer *buffer, ancillary_data_container *container) 1857 { 1858 ((net_buffer_private*)buffer)->ancillary_data = container; 1859 } 1860 1861 1862 ancillary_data_container* 1863 get_ancillary_data(net_buffer *buffer) 1864 { 1865 return ((net_buffer_private*)buffer)->ancillary_data; 1866 } 1867 1868 1869 /*! 1870 Moves all ancillary data from buffer \c from to the end of the list of 1871 ancillary data of buffer \c to. Note, that this is the only function that 1872 transfers or copies ancillary data from one buffer to another. 1873 1874 \param from The buffer from which to remove the ancillary data. 1875 \param to The buffer to which to add the ancillary data. 1876 \return A pointer to the first of the moved ancillary data, if any, \c NULL 1877 otherwise. 1878 */ 1879 static void * 1880 transfer_ancillary_data(net_buffer *_from, net_buffer *_to) 1881 { 1882 net_buffer_private *from = (net_buffer_private *)_from; 1883 net_buffer_private *to = (net_buffer_private *)_to; 1884 1885 if (from == NULL || to == NULL) 1886 return NULL; 1887 1888 if (from->ancillary_data == NULL) 1889 return NULL; 1890 1891 if (to->ancillary_data == NULL) { 1892 // no ancillary data in the target buffer 1893 to->ancillary_data = from->ancillary_data; 1894 from->ancillary_data = NULL; 1895 return next_ancillary_data(to->ancillary_data, NULL, NULL); 1896 } 1897 1898 // both have ancillary data 1899 void *data = move_ancillary_data(from->ancillary_data, 1900 to->ancillary_data); 1901 delete_ancillary_data_container(from->ancillary_data); 1902 from->ancillary_data = NULL; 1903 1904 return data; 1905 } 1906 1907 1908 /*! 1909 Tries to directly access the requested space in the buffer. 1910 If the space is contiguous, the function will succeed and place a pointer 1911 to that space into \a _contiguousBuffer. 1912 1913 \return B_BAD_VALUE if the offset is outside of the buffer's bounds. 1914 \return B_ERROR in case the buffer is not contiguous at that location. 1915 */ 1916 static status_t 1917 direct_access(net_buffer *_buffer, uint32 offset, size_t size, 1918 void **_contiguousBuffer) 1919 { 1920 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1921 1922 ParanoiaChecker _(buffer); 1923 1924 //TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, size)); 1925 1926 if (offset + size > buffer->size) 1927 return B_BAD_VALUE; 1928 1929 // find node to access 1930 data_node *node = get_node_at_offset(buffer, offset); 1931 if (node == NULL) 1932 return B_BAD_VALUE; 1933 1934 offset -= node->offset; 1935 1936 if (size > node->used - offset) 1937 return B_ERROR; 1938 1939 *_contiguousBuffer = node->start + offset; 1940 return B_OK; 1941 } 1942 1943 1944 static int32 1945 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize) 1946 { 1947 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1948 1949 if (offset + size > buffer->size || size == 0) 1950 return B_BAD_VALUE; 1951 1952 // find first node to read from 1953 data_node *node = get_node_at_offset(buffer, offset); 1954 if (node == NULL) 1955 return B_ERROR; 1956 1957 offset -= node->offset; 1958 1959 // Since the maximum buffer size is 65536 bytes, it's impossible 1960 // to overlap 32 bit - we don't need to handle this overlap in 1961 // the loop, we can safely do it afterwards 1962 uint32 sum = 0; 1963 1964 while (true) { 1965 size_t bytes = min_c(size, node->used - offset); 1966 if ((offset + node->offset) & 1) { 1967 // if we're at an uneven offset, we have to swap the checksum 1968 sum += __swap_int16(compute_checksum(node->start + offset, bytes)); 1969 } else 1970 sum += compute_checksum(node->start + offset, bytes); 1971 1972 size -= bytes; 1973 if (size == 0) 1974 break; 1975 1976 offset = 0; 1977 1978 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1979 if (node == NULL) 1980 return B_ERROR; 1981 } 1982 1983 while (sum >> 16) { 1984 sum = (sum & 0xffff) + (sum >> 16); 1985 } 1986 1987 if (!finalize) 1988 return (uint16)sum; 1989 1990 return (uint16)~sum; 1991 } 1992 1993 1994 static uint32 1995 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount) 1996 { 1997 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1998 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 1999 uint32 count = 0; 2000 2001 while (node != NULL && count < vecCount) { 2002 if (node->used > 0) { 2003 iovecs[count].iov_base = node->start; 2004 iovecs[count].iov_len = node->used; 2005 count++; 2006 } 2007 2008 node = (data_node *)list_get_next_item(&buffer->buffers, node); 2009 } 2010 2011 return count; 2012 } 2013 2014 2015 static uint32 2016 count_iovecs(net_buffer *_buffer) 2017 { 2018 net_buffer_private *buffer = (net_buffer_private *)_buffer; 2019 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 2020 uint32 count = 0; 2021 2022 while (node != NULL) { 2023 if (node->used > 0) 2024 count++; 2025 2026 node = (data_node *)list_get_next_item(&buffer->buffers, node); 2027 } 2028 2029 return count; 2030 } 2031 2032 2033 static void 2034 swap_addresses(net_buffer *buffer) 2035 { 2036 std::swap(buffer->source, buffer->destination); 2037 } 2038 2039 2040 static status_t 2041 std_ops(int32 op, ...) 2042 { 2043 switch (op) { 2044 case B_MODULE_INIT: 2045 // TODO: improve our code a bit so we can add constructors 2046 // and keep around half-constructed buffers in the slab 2047 2048 sNetBufferCache = create_object_cache("net buffer cache", 2049 sizeof(net_buffer_private), 8, NULL, NULL, NULL); 2050 if (sNetBufferCache == NULL) 2051 return B_NO_MEMORY; 2052 2053 sDataNodeCache = create_object_cache("data node cache", BUFFER_SIZE, 2054 0, NULL, NULL, NULL); 2055 if (sDataNodeCache == NULL) { 2056 delete_object_cache(sNetBufferCache); 2057 return B_NO_MEMORY; 2058 } 2059 2060 #if ENABLE_DEBUGGER_COMMANDS 2061 add_debugger_command_etc("net_buffer_stats", &dump_net_buffer_stats, 2062 "Print net buffer statistics", 2063 "\nPrint net buffer statistics.\n", 0); 2064 #endif 2065 2066 return B_OK; 2067 2068 case B_MODULE_UNINIT: 2069 #if ENABLE_DEBUGGER_COMMANDS 2070 remove_debugger_command("net_buffer_stats", &dump_net_buffer_stats); 2071 #endif 2072 delete_object_cache(sNetBufferCache); 2073 delete_object_cache(sDataNodeCache); 2074 return B_OK; 2075 2076 default: 2077 return B_ERROR; 2078 } 2079 } 2080 2081 2082 net_buffer_module_info gNetBufferModule = { 2083 { 2084 NET_BUFFER_MODULE_NAME, 2085 0, 2086 std_ops 2087 }, 2088 create_buffer, 2089 free_buffer, 2090 2091 duplicate_buffer, 2092 clone_buffer, 2093 split_buffer, 2094 merge_buffer, 2095 2096 prepend_size, 2097 prepend_data, 2098 append_size, 2099 append_data, 2100 NULL, // insert 2101 NULL, // remove 2102 remove_header, 2103 remove_trailer, 2104 trim_data, 2105 append_cloned_data, 2106 2107 NULL, // associate_data 2108 2109 set_ancillary_data, 2110 get_ancillary_data, 2111 transfer_ancillary_data, 2112 2113 direct_access, 2114 read_data, 2115 write_data, 2116 2117 checksum_data, 2118 2119 NULL, // get_memory_map 2120 get_iovecs, 2121 count_iovecs, 2122 2123 swap_addresses, 2124 2125 dump_buffer, // dump 2126 }; 2127 2128