1 /* 2 * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "utility.h" 11 12 #include <net_buffer.h> 13 #include <slab/Slab.h> 14 #include <util/list.h> 15 16 #include <ByteOrder.h> 17 #include <KernelExport.h> 18 #include <util/AutoLock.h> 19 20 #include <algorithm> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/uio.h> 24 25 26 //#define TRACE_BUFFER 27 #ifdef TRACE_BUFFER 28 # define TRACE(x) dprintf x 29 #else 30 # define TRACE(x) ; 31 #endif 32 33 #define BUFFER_SIZE 2048 34 // maximum implementation derived buffer size is 65536 35 36 struct data_node { 37 struct list_link link; 38 struct data_header *header; 39 struct data_header *located; 40 size_t offset; // the net_buffer-wide offset of this node 41 uint8 *start; // points to the start of the data 42 uint16 used; // defines how much memory is used by this node 43 uint16 header_space; 44 uint16 tail_space; 45 }; 46 47 struct free_data { 48 struct free_data *next; 49 uint16 size; 50 }; 51 52 struct data_header { 53 int32 ref_count; 54 addr_t physical_address; 55 free_data *first_free; 56 uint8 *data_end; 57 size_t data_space; 58 data_node *first_node; 59 }; 60 61 #define MAX_FREE_BUFFER_SIZE (BUFFER_SIZE - sizeof(data_header)) 62 63 struct net_buffer_private : net_buffer { 64 struct list buffers; 65 data_node first_node; 66 67 struct { 68 struct sockaddr_storage source; 69 struct sockaddr_storage destination; 70 } storage; 71 }; 72 73 74 static object_cache *sNetBufferCache; 75 static object_cache *sDataNodeCache; 76 77 78 static status_t append_data(net_buffer *buffer, const void *data, size_t size); 79 static status_t trim_data(net_buffer *_buffer, size_t newSize); 80 static status_t remove_header(net_buffer *_buffer, size_t bytes); 81 static status_t remove_trailer(net_buffer *_buffer, size_t bytes); 82 83 84 #if 1 85 static void 86 dump_buffer(net_buffer *_buffer) 87 { 88 net_buffer_private *buffer = (net_buffer_private *)_buffer; 89 90 dprintf("buffer %p, size %ld\n", buffer, buffer->size); 91 data_node *node = NULL; 92 while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) { 93 dprintf(" node %p, offset %lu, used %u, header %u, tail %u, header %p\n", 94 node, node->offset, node->used, node->header_space, node->tail_space, node->header); 95 //dump_block((char *)node->start, node->used, " "); 96 dump_block((char *)node->start, min_c(node->used, 32), " "); 97 } 98 } 99 #endif 100 101 102 static inline data_header * 103 allocate_data_header() 104 { 105 return (data_header *)object_cache_alloc(sDataNodeCache, CACHE_DONT_SLEEP); 106 } 107 108 109 static inline net_buffer_private * 110 allocate_net_buffer() 111 { 112 return (net_buffer_private *)object_cache_alloc(sNetBufferCache, 113 CACHE_DONT_SLEEP); 114 } 115 116 117 static inline void 118 free_data_header(data_header *header) 119 { 120 object_cache_free(sDataNodeCache, header); 121 } 122 123 124 static inline void 125 free_net_buffer(net_buffer_private *buffer) 126 { 127 object_cache_free(sNetBufferCache, buffer); 128 } 129 130 131 static data_header * 132 create_data_header(size_t headerSpace) 133 { 134 data_header *header = allocate_data_header(); 135 if (header == NULL) 136 return NULL; 137 138 header->ref_count = 1; 139 header->physical_address = 0; 140 // TODO: initialize this correctly 141 header->data_space = headerSpace; 142 header->data_end = (uint8 *)header + sizeof(struct data_header); 143 header->first_free = NULL; 144 header->first_node = NULL; 145 146 TRACE((" create new data header %p\n", header)); 147 return header; 148 } 149 150 151 static void 152 release_data_header(data_header *header) 153 { 154 if (atomic_add(&header->ref_count, -1) != 1) 155 return; 156 157 TRACE((" free header %p\n", header)); 158 free_data_header(header); 159 } 160 161 162 inline void 163 acquire_data_header(data_header *header) 164 { 165 atomic_add(&header->ref_count, 1); 166 } 167 168 169 static void 170 free_data_header_space(data_header *header, uint8 *data, size_t size) 171 { 172 if (size < sizeof(free_data)) 173 size = sizeof(free_data); 174 175 free_data *freeData = (free_data *)data; 176 freeData->next = header->first_free; 177 freeData->size = size; 178 179 header->first_free = freeData; 180 header->data_space += size; 181 // TODO: the first node's header space could grow again 182 } 183 184 185 /*! 186 Tries to allocate \a size bytes from the free space in the header. 187 */ 188 static uint8 * 189 alloc_data_header_space(data_header *header, size_t size) 190 { 191 if (size < sizeof(free_data)) 192 size = sizeof(free_data); 193 194 if (header->first_free != NULL && header->first_free->size >= size) { 195 // the first entry of the header space matches the allocation's needs 196 uint8 *data = (uint8 *)header->first_free; 197 header->first_free = header->first_free->next; 198 return data; 199 } 200 201 if (header->data_space < size) { 202 // there is no free space left, search free list 203 free_data *freeData = header->first_free; 204 free_data *last = NULL; 205 while (freeData != NULL) { 206 if (last != NULL && freeData->size >= size) { 207 // take this one 208 last->next = freeData->next; 209 return (uint8 *)freeData; 210 } 211 212 last = freeData; 213 freeData = freeData->next; 214 } 215 216 return NULL; 217 } 218 219 // allocate new space 220 221 uint8 *data = header->data_end; 222 header->data_end += size; 223 header->data_space -= size; 224 225 if (header->first_node != NULL) 226 header->first_node->header_space -= size; 227 228 return data; 229 } 230 231 232 /*! 233 Initializes the first data_node of a data_header. 234 The node must have been assigned to the header already. 235 */ 236 static void 237 init_first_data_node(data_node *node) 238 { 239 data_header *header = node->header; 240 241 node->offset = 0; 242 node->start = header->data_end + header->data_space; 243 node->used = 0; 244 node->header_space = header->data_space; 245 node->tail_space = MAX_FREE_BUFFER_SIZE - header->data_space; 246 247 header->first_node = node; 248 } 249 250 251 static data_node * 252 add_data_node(data_header *header, data_header *located = NULL) 253 { 254 if (located == NULL) 255 located = header; 256 257 data_node *node = (data_node *)alloc_data_header_space(located, 258 sizeof(data_node)); 259 if (node == NULL) 260 return NULL; 261 262 TRACE((" add data node %p to header %p\n", node, header)); 263 acquire_data_header(header); 264 if (located != header) 265 acquire_data_header(located); 266 267 memset(node, 0, sizeof(struct data_node)); 268 node->located = located; 269 node->header = header; 270 return node; 271 } 272 273 274 void 275 remove_data_node(data_node *node) 276 { 277 data_header *located = node->located; 278 279 TRACE((" remove data node %p from header %p (located %p)\n", 280 node, node->header, located)); 281 282 if (located != node->header) 283 release_data_header(node->header); 284 285 if (located == NULL) 286 return; 287 288 free_data_header_space(located, (uint8 *)node, sizeof(data_node)); 289 if (located->first_node == node) { 290 located->first_node = NULL; 291 located->data_space = 0; 292 } 293 294 release_data_header(located); 295 } 296 297 298 static inline data_node * 299 get_node_at_offset(net_buffer_private *buffer, size_t offset) 300 { 301 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 302 while (node->offset + node->used < offset) { 303 node = (data_node *)list_get_next_item(&buffer->buffers, node); 304 if (node == NULL) 305 return NULL; 306 } 307 308 return node; 309 } 310 311 312 // #pragma mark - 313 314 315 static net_buffer * 316 create_buffer(size_t headerSpace) 317 { 318 net_buffer_private *buffer = allocate_net_buffer(); 319 if (buffer == NULL) 320 return NULL; 321 322 TRACE(("create buffer %p\n", buffer)); 323 324 data_header *header = create_data_header(headerSpace); 325 if (header == NULL) { 326 free_net_buffer(buffer); 327 return NULL; 328 } 329 330 buffer->first_node.header = header; 331 buffer->first_node.located = NULL; 332 init_first_data_node(&buffer->first_node); 333 334 list_init(&buffer->buffers); 335 list_add_item(&buffer->buffers, &buffer->first_node); 336 337 buffer->source = (sockaddr *)&buffer->storage.source; 338 buffer->destination = (sockaddr *)&buffer->storage.destination; 339 340 buffer->storage.source.ss_len = 0; 341 buffer->storage.destination.ss_len = 0; 342 343 buffer->interface = NULL; 344 buffer->offset = 0; 345 buffer->flags = 0; 346 buffer->size = 0; 347 348 buffer->type = -1; 349 350 return buffer; 351 } 352 353 354 static void 355 free_buffer(net_buffer *_buffer) 356 { 357 net_buffer_private *buffer = (net_buffer_private *)_buffer; 358 359 TRACE(("free buffer %p\n", buffer)); 360 361 data_node *node; 362 while ((node = (data_node *)list_remove_head_item(&buffer->buffers)) != NULL) { 363 remove_data_node(node); 364 } 365 366 free_net_buffer(buffer); 367 } 368 369 370 static void 371 copy_metadata(net_buffer *destination, const net_buffer *source) 372 { 373 memcpy(destination->source, source->source, 374 min_c(source->source->sa_len, sizeof(sockaddr_storage))); 375 memcpy(destination->destination, source->destination, 376 min_c(source->destination->sa_len, sizeof(sockaddr_storage))); 377 378 destination->flags = source->flags; 379 destination->interface = source->interface; 380 destination->offset = source->offset; 381 destination->size = source->size; 382 destination->protocol = source->protocol; 383 destination->type = source->type; 384 } 385 386 387 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal 388 storage; they are completely independent from each other. 389 */ 390 static net_buffer * 391 duplicate_buffer(net_buffer *_buffer) 392 { 393 net_buffer_private *buffer = (net_buffer_private *)_buffer; 394 395 net_buffer *duplicate = create_buffer(buffer->first_node.header_space); 396 if (duplicate == NULL) 397 return NULL; 398 399 // copy the data from the source buffer 400 401 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 402 while (true) { 403 if (append_data(duplicate, node->start, node->used) < B_OK) { 404 free_buffer(duplicate); 405 return NULL; 406 } 407 408 node = (data_node *)list_get_next_item(&buffer->buffers, node); 409 if (node == NULL) 410 break; 411 } 412 413 copy_metadata(duplicate, buffer); 414 415 return duplicate; 416 } 417 418 419 /*! Clones the buffer by grabbing another reference to the underlying data. 420 If that data changes, it will be changed in the clone as well. 421 422 If \a shareFreeSpace is \c true, the cloned buffer may claim the free 423 space in the original buffer as the original buffer can still do. If you 424 are using this, it's your responsibility that only one of the buffers 425 will do this. 426 */ 427 static net_buffer * 428 clone_buffer(net_buffer *_buffer, bool shareFreeSpace) 429 { 430 net_buffer_private *buffer = (net_buffer_private *)_buffer; 431 432 TRACE(("clone_buffer(buffer %p)\n", buffer)); 433 434 net_buffer_private *clone = allocate_net_buffer(); 435 if (clone == NULL) 436 return NULL; 437 438 data_node *sourceNode = (data_node *)list_get_first_item(&buffer->buffers); 439 if (sourceNode == NULL) { 440 free_net_buffer(clone); 441 return NULL; 442 } 443 444 clone->source = (sockaddr *)&clone->storage.source; 445 clone->destination = (sockaddr *)&clone->storage.destination; 446 447 list_init(&clone->buffers); 448 449 // grab reference to this buffer - all additional nodes will get 450 // theirs in add_data_node() 451 acquire_data_header(sourceNode->header); 452 data_node *node = &clone->first_node; 453 node->header = sourceNode->header; 454 node->located = NULL; 455 456 while (sourceNode != NULL) { 457 node->start = sourceNode->start; 458 node->used = sourceNode->used; 459 node->offset = sourceNode->offset; 460 461 if (shareFreeSpace) { 462 // both buffers could claim the free space - note that this option 463 // has to be used carefully 464 node->header_space = sourceNode->header_space; 465 node->tail_space = sourceNode->tail_space; 466 } else { 467 // the free space stays with the original buffer 468 node->header_space = 0; 469 node->tail_space = 0; 470 } 471 472 // add node to clone's list of buffers 473 list_add_item(&clone->buffers, node); 474 475 sourceNode = (data_node *)list_get_next_item(&buffer->buffers, sourceNode); 476 if (sourceNode == NULL) 477 break; 478 479 node = add_data_node(sourceNode->header); 480 if (node == NULL) { 481 // There was not enough space left for another node in this buffer 482 // TODO: handle this case! 483 panic("clone buffer hits size limit... (fix me)"); 484 free_net_buffer(clone); 485 return NULL; 486 } 487 } 488 489 copy_metadata(clone, buffer); 490 491 return clone; 492 } 493 494 495 /*! 496 Split the buffer at offset, the header data 497 is returned as new buffer. 498 TODO: optimize and avoid making a copy. 499 */ 500 static net_buffer * 501 split_buffer(net_buffer *from, uint32 offset) 502 { 503 net_buffer *buffer = duplicate_buffer(from); 504 if (buffer == NULL) 505 return NULL; 506 507 TRACE(("split_buffer(buffer %p -> %p, offset %ld)\n", from, buffer, offset)); 508 509 if (trim_data(buffer, offset) == B_OK) { 510 if (remove_header(from, offset) == B_OK) 511 return buffer; 512 } 513 514 free_buffer(buffer); 515 return NULL; 516 } 517 518 519 /*! 520 Merges the second buffer with the first. If \a after is \c true, the 521 second buffer's contents will be appended to the first ones, else they 522 will be prepended. 523 The second buffer will be freed if this function succeeds. 524 */ 525 static status_t 526 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after) 527 { 528 net_buffer_private *buffer = (net_buffer_private *)_buffer; 529 net_buffer_private *with = (net_buffer_private *)_with; 530 if (with == NULL) 531 return B_BAD_VALUE; 532 533 TRACE(("merge buffer %p with %p (%s)\n", buffer, with, after ? "after" : "before")); 534 //dump_buffer(buffer); 535 //dprintf("with:\n"); 536 //dump_buffer(with); 537 538 // TODO: this is currently very simplistic, I really need to finish the 539 // harder part of this implementation (data_node management per header) 540 541 data_node *before = NULL; 542 543 if (!after) { 544 // change offset of all nodes already in the buffer 545 data_node *node = NULL; 546 while (true) { 547 node = (data_node *)list_get_next_item(&buffer->buffers, node); 548 if (node == NULL) 549 break; 550 551 node->offset += with->size; 552 if (before == NULL) 553 before = node; 554 } 555 } 556 557 data_node *last = NULL; 558 559 while (true) { 560 data_node *node = (data_node *)list_get_next_item(&with->buffers, last); 561 if (node == NULL) 562 break; 563 564 if ((uint8 *)node > (uint8 *)node->header 565 && (uint8 *)node < (uint8 *)node->header + BUFFER_SIZE) { 566 // The node is already in the buffer, we can just move it 567 // over to the new owner 568 list_remove_item(&with->buffers, node); 569 } else { 570 // we need a new place for this node 571 data_node *newNode = add_data_node(node->header); 572 if (newNode == NULL) { 573 // try again on the buffers own header 574 newNode = add_data_node(node->header, buffer->first_node.header); 575 if (newNode == NULL) 576 // TODO: try to revert buffers to their initial state!! 577 return ENOBUFS; 578 } 579 580 last = node; 581 *newNode = *node; 582 node = newNode; 583 // the old node will get freed with its buffer 584 } 585 586 if (after) { 587 list_add_item(&buffer->buffers, node); 588 node->offset = buffer->size; 589 } else 590 list_insert_item_before(&buffer->buffers, before, node); 591 592 buffer->size += node->used; 593 } 594 595 // the data has been merged completely at this point 596 free_buffer(with); 597 598 //dprintf(" merge result:\n"); 599 //dump_buffer(buffer); 600 return B_OK; 601 } 602 603 604 /*! Writes into existing allocated memory. 605 \return B_BAD_VALUE if you write outside of the buffers current 606 bounds. 607 */ 608 static status_t 609 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size) 610 { 611 net_buffer_private *buffer = (net_buffer_private *)_buffer; 612 613 if (offset + size > buffer->size) 614 return B_BAD_VALUE; 615 if (size == 0) 616 return B_OK; 617 618 // find first node to write into 619 data_node *node = get_node_at_offset(buffer, offset); 620 if (node == NULL) 621 return B_BAD_VALUE; 622 623 offset -= node->offset; 624 625 while (true) { 626 size_t written = min_c(size, node->used - offset); 627 memcpy(node->start + offset, data, written); 628 629 size -= written; 630 if (size == 0) 631 break; 632 633 offset = 0; 634 data = (void *)((uint8 *)data + written); 635 636 node = (data_node *)list_get_next_item(&buffer->buffers, node); 637 if (node == NULL) 638 return B_BAD_VALUE; 639 } 640 641 return B_OK; 642 } 643 644 645 static status_t 646 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size) 647 { 648 net_buffer_private *buffer = (net_buffer_private *)_buffer; 649 650 if (offset + size > buffer->size) 651 return B_BAD_VALUE; 652 if (size == 0) 653 return B_OK; 654 655 // find first node to read from 656 data_node *node = get_node_at_offset(buffer, offset); 657 if (node == NULL) 658 return B_BAD_VALUE; 659 660 offset -= node->offset; 661 662 while (true) { 663 size_t bytesRead = min_c(size, node->used - offset); 664 memcpy(data, node->start + offset, bytesRead); 665 666 size -= bytesRead; 667 if (size == 0) 668 break; 669 670 offset = 0; 671 data = (void *)((uint8 *)data + bytesRead); 672 673 node = (data_node *)list_get_next_item(&buffer->buffers, node); 674 if (node == NULL) 675 return B_BAD_VALUE; 676 } 677 678 return B_OK; 679 } 680 681 682 static status_t 683 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 684 { 685 net_buffer_private *buffer = (net_buffer_private *)_buffer; 686 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 687 688 TRACE(("prepend_size(buffer %p, size %ld) [has %ld]\n", buffer, size, 689 node->header_space)); 690 //dump_buffer(buffer); 691 692 if (node->header_space < size) { 693 // we need to prepend new buffers 694 695 size_t bytesLeft = size; 696 do { 697 if (node->header_space == 0) { 698 size_t headerSpace = MAX_FREE_BUFFER_SIZE; 699 data_header *header = create_data_header(headerSpace); 700 if (header == NULL) { 701 // TODO: free up headers we already allocated! 702 return B_NO_MEMORY; 703 } 704 705 data_node *previous = node; 706 707 node = (data_node *)add_data_node(header); 708 init_first_data_node(node); 709 710 list_insert_item_before(&buffer->buffers, previous, node); 711 } 712 713 size_t willConsume = min_c(bytesLeft, node->header_space); 714 715 node->header_space -= willConsume; 716 node->start -= willConsume; 717 node->used += willConsume; 718 bytesLeft -= willConsume; 719 } while (bytesLeft > 0); 720 721 // correct data offset in all nodes 722 723 size_t offset = 0; 724 node = NULL; 725 while ((node = (data_node *)list_get_next_item(&buffer->buffers, 726 node)) != NULL) { 727 node->offset = offset; 728 offset += node->used; 729 } 730 731 if (_contiguousBuffer) 732 *_contiguousBuffer = NULL; 733 } else { 734 // the data fits into this buffer 735 node->header_space -= size; 736 node->start -= size; 737 node->used += size; 738 739 if (_contiguousBuffer) 740 *_contiguousBuffer = node->start; 741 742 // adjust offset of following nodes 743 while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) { 744 node->offset += size; 745 } 746 } 747 748 buffer->size += size; 749 750 //dprintf(" prepend_size result:\n"); 751 //dump_buffer(buffer); 752 return B_OK; 753 } 754 755 756 static status_t 757 prepend_data(net_buffer *buffer, const void *data, size_t size) 758 { 759 void *contiguousBuffer; 760 status_t status = prepend_size(buffer, size, &contiguousBuffer); 761 if (status < B_OK) 762 return status; 763 764 if (contiguousBuffer) 765 memcpy(contiguousBuffer, data, size); 766 else 767 write_data(buffer, 0, data, size); 768 769 //dprintf(" prepend result:\n"); 770 //dump_buffer(buffer); 771 772 return B_OK; 773 } 774 775 776 static status_t 777 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer) 778 { 779 net_buffer_private *buffer = (net_buffer_private *)_buffer; 780 data_node *node = (data_node *)list_get_last_item(&buffer->buffers); 781 782 TRACE(("append_size(buffer %p, size %ld)\n", buffer, size)); 783 //dump_buffer(buffer); 784 785 if (node->tail_space < size) { 786 // we need to append a new buffer 787 788 // compute how many buffers we're going to need 789 // TODO: this doesn't leave any tail space, if that should be desired... 790 uint32 tailSpace = node->tail_space; 791 uint32 minimalHeaderSpace = sizeof(data_header) + 3 * sizeof(data_node); 792 uint32 sizeNeeded = size - tailSpace; 793 uint32 count = (sizeNeeded + BUFFER_SIZE - minimalHeaderSpace - 1) 794 / (BUFFER_SIZE - minimalHeaderSpace); 795 uint32 headerSpace = BUFFER_SIZE - sizeNeeded / count - sizeof(data_header); 796 uint32 sizeUsed = MAX_FREE_BUFFER_SIZE - headerSpace; 797 uint32 sizeAdded = tailSpace; 798 799 // allocate space left in the node 800 node->tail_space -= tailSpace; 801 node->used += tailSpace; 802 buffer->size += tailSpace; 803 804 // allocate all buffers 805 806 for (uint32 i = 0; i < count; i++) { 807 if (i == count - 1) { 808 // last data_header - compensate rounding errors 809 sizeUsed = size - sizeAdded; 810 headerSpace = MAX_FREE_BUFFER_SIZE - sizeUsed; 811 } 812 813 data_header *header = create_data_header(headerSpace); 814 if (header == NULL) { 815 // TODO: free up headers we already allocated! 816 return B_NO_MEMORY; 817 } 818 819 node = (data_node *)add_data_node(header); 820 // this can't fail as we made sure there will be enough header space 821 822 init_first_data_node(node); 823 node->tail_space -= sizeUsed; 824 node->used = sizeUsed; 825 node->offset = buffer->size; 826 827 buffer->size += sizeUsed; 828 sizeAdded += sizeUsed; 829 830 list_add_item(&buffer->buffers, node); 831 } 832 833 if (_contiguousBuffer) 834 *_contiguousBuffer = NULL; 835 836 //dprintf(" append result 1:\n"); 837 //dump_buffer(buffer); 838 return B_OK; 839 } 840 841 // the data fits into this buffer 842 node->tail_space -= size; 843 844 if (_contiguousBuffer) 845 *_contiguousBuffer = node->start + node->used; 846 847 node->used += size; 848 buffer->size += size; 849 850 //dprintf(" append result 2:\n"); 851 //dump_buffer(buffer); 852 return B_OK; 853 } 854 855 856 static status_t 857 append_data(net_buffer *buffer, const void *data, size_t size) 858 { 859 size_t used = buffer->size; 860 861 void *contiguousBuffer; 862 status_t status = append_size(buffer, size, &contiguousBuffer); 863 if (status < B_OK) 864 return status; 865 866 if (contiguousBuffer) 867 memcpy(contiguousBuffer, data, size); 868 else 869 write_data(buffer, used, data, size); 870 871 return B_OK; 872 } 873 874 875 /*! 876 Removes bytes from the beginning of the buffer. 877 */ 878 static status_t 879 remove_header(net_buffer *_buffer, size_t bytes) 880 { 881 net_buffer_private *buffer = (net_buffer_private *)_buffer; 882 883 if (bytes > buffer->size) 884 return B_BAD_VALUE; 885 886 TRACE(("remove_header(buffer %p, %ld bytes)\n", buffer, bytes)); 887 //dump_buffer(buffer); 888 889 size_t left = bytes; 890 data_node *node = NULL; 891 892 while (left >= 0) { 893 node = (data_node *)list_get_first_item(&buffer->buffers); 894 if (node == NULL) { 895 if (left == 0) 896 break; 897 return B_ERROR; 898 } 899 900 if (node->used > left) 901 break; 902 903 // node will be removed completely 904 list_remove_item(&buffer->buffers, node); 905 left -= node->used; 906 remove_data_node(node); 907 node = NULL; 908 } 909 910 // cut remaining node, if any 911 912 if (node != NULL) { 913 size_t cut = min_c(node->used, left); 914 node->offset = 0; 915 node->start += cut; 916 node->header_space += cut; 917 node->used -= cut; 918 919 node = (data_node *)list_get_next_item(&buffer->buffers, node); 920 } 921 922 // adjust offset of following nodes 923 while (node != NULL) { 924 node->offset -= bytes; 925 node = (data_node *)list_get_next_item(&buffer->buffers, node); 926 } 927 928 buffer->size -= bytes; 929 930 //dprintf(" remove result:\n"); 931 //dump_buffer(buffer); 932 return B_OK; 933 } 934 935 936 /*! 937 Removes bytes from the end of the buffer. 938 */ 939 static status_t 940 remove_trailer(net_buffer *buffer, size_t bytes) 941 { 942 return trim_data(buffer, buffer->size - bytes); 943 } 944 945 946 /*! 947 Trims the buffer to the specified \a newSize by removing space from 948 the end of the buffer. 949 */ 950 static status_t 951 trim_data(net_buffer *_buffer, size_t newSize) 952 { 953 net_buffer_private *buffer = (net_buffer_private *)_buffer; 954 TRACE(("trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n", 955 buffer, newSize, buffer->size)); 956 //dump_buffer(buffer); 957 958 if (newSize > buffer->size) 959 return B_BAD_VALUE; 960 if (newSize == buffer->size) 961 return B_OK; 962 963 data_node *node = get_node_at_offset(buffer, newSize); 964 if (node == NULL) { 965 // trim size greater than buffer size 966 return B_BAD_VALUE; 967 } 968 969 int32 diff = node->used + node->offset - newSize; 970 node->tail_space += diff; 971 node->used -= diff; 972 973 if (node->used > 0) 974 node = (data_node *)list_get_next_item(&buffer->buffers, node); 975 976 while (node != NULL) { 977 data_node *next = (data_node *)list_get_next_item(&buffer->buffers, node); 978 list_remove_item(&buffer->buffers, node); 979 remove_data_node(node); 980 981 node = next; 982 } 983 984 buffer->size = newSize; 985 986 //dprintf(" trim result:\n"); 987 //dump_buffer(buffer); 988 return B_OK; 989 } 990 991 992 /*! 993 Appends data coming from buffer \a source to the buffer \a buffer. It only 994 clones the data, though, that is the data is not copied, just referenced. 995 */ 996 status_t 997 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset, 998 size_t bytes) 999 { 1000 if (bytes == 0) 1001 return B_OK; 1002 1003 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1004 net_buffer_private *source = (net_buffer_private *)_source; 1005 TRACE(("append_cloned_data(buffer %p, source %p, offset = %ld, bytes = %ld)\n", 1006 buffer, source, offset, bytes)); 1007 1008 if (source->size < offset + bytes || source->size < offset) 1009 return B_BAD_VALUE; 1010 1011 // find data_node to start with from the source buffer 1012 data_node *node = get_node_at_offset(source, offset); 1013 if (node == NULL) { 1014 // trim size greater than buffer size 1015 return B_BAD_VALUE; 1016 } 1017 1018 while (node != NULL && bytes > 0) { 1019 data_node *clone = add_data_node(node->header, buffer->first_node.header); 1020 if (clone == NULL) 1021 clone = add_data_node(node->header); 1022 if (clone == NULL) { 1023 // There is not enough space in the buffer for another node 1024 // TODO: handle this case! 1025 dump_buffer(buffer); 1026 dprintf("SOURCE:\n"); 1027 dump_buffer(source); 1028 panic("appending clone buffer in new header not implemented\n"); 1029 return ENOBUFS; 1030 } 1031 1032 if (offset) 1033 offset -= node->offset; 1034 1035 clone->offset = buffer->size; 1036 clone->start = node->start + offset; 1037 clone->used = min_c(bytes, node->used - offset); 1038 clone->header_space = 0; 1039 clone->tail_space = 0; 1040 1041 list_add_item(&buffer->buffers, clone); 1042 1043 offset = 0; 1044 bytes -= clone->used; 1045 buffer->size += clone->used; 1046 node = (data_node *)list_get_next_item(&source->buffers, node); 1047 } 1048 1049 if (bytes != 0) 1050 panic("add_cloned_data() failed, bytes != 0!\n"); 1051 1052 //dprintf(" append cloned result:\n"); 1053 //dump_buffer(buffer); 1054 return B_OK; 1055 } 1056 1057 1058 /*! 1059 Tries to directly access the requested space in the buffer. 1060 If the space is contiguous, the function will succeed and place a pointer 1061 to that space into \a _contiguousBuffer. 1062 1063 \return B_BAD_VALUE if the offset is outside of the buffer's bounds. 1064 \return B_ERROR in case the buffer is not contiguous at that location. 1065 */ 1066 static status_t 1067 direct_access(net_buffer *_buffer, uint32 offset, size_t size, 1068 void **_contiguousBuffer) 1069 { 1070 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1071 1072 //TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, size)); 1073 1074 if (offset + size > buffer->size) 1075 return B_BAD_VALUE; 1076 1077 // find node to access 1078 data_node *node = get_node_at_offset(buffer, offset); 1079 if (node == NULL) 1080 return B_BAD_VALUE; 1081 1082 offset -= node->offset; 1083 1084 if (size > node->used - offset) 1085 return B_ERROR; 1086 1087 *_contiguousBuffer = node->start + offset; 1088 return B_OK; 1089 } 1090 1091 1092 static int32 1093 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize) 1094 { 1095 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1096 1097 if (offset + size > buffer->size || size == 0) 1098 return B_BAD_VALUE; 1099 1100 // find first node to read from 1101 data_node *node = get_node_at_offset(buffer, offset); 1102 if (node == NULL) 1103 return B_ERROR; 1104 1105 offset -= node->offset; 1106 1107 // Since the maximum buffer size is 65536 bytes, it's impossible 1108 // to overlap 32 bit - we don't need to handle this overlap in 1109 // the loop, we can safely do it afterwards 1110 uint32 sum = 0; 1111 1112 while (true) { 1113 size_t bytes = min_c(size, node->used - offset); 1114 if ((offset + node->offset) & 1) { 1115 // if we're at an uneven offset, we have to swap the checksum 1116 sum += __swap_int16(compute_checksum(node->start + offset, bytes)); 1117 } else 1118 sum += compute_checksum(node->start + offset, bytes); 1119 1120 size -= bytes; 1121 if (size == 0) 1122 break; 1123 1124 offset = 0; 1125 1126 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1127 if (node == NULL) 1128 return B_ERROR; 1129 } 1130 1131 while (sum >> 16) { 1132 sum = (sum & 0xffff) + (sum >> 16); 1133 } 1134 1135 if (!finalize) 1136 return (uint16)sum; 1137 1138 return (uint16)~sum; 1139 } 1140 1141 1142 static uint32 1143 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount) 1144 { 1145 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1146 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 1147 uint32 count = 0; 1148 1149 while (node != NULL && count < vecCount) { 1150 if (node->used > 0) { 1151 iovecs[count].iov_base = node->start; 1152 iovecs[count].iov_len = node->used; 1153 count++; 1154 } 1155 1156 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1157 } 1158 1159 return count; 1160 } 1161 1162 1163 static uint32 1164 count_iovecs(net_buffer *_buffer) 1165 { 1166 net_buffer_private *buffer = (net_buffer_private *)_buffer; 1167 data_node *node = (data_node *)list_get_first_item(&buffer->buffers); 1168 uint32 count = 0; 1169 1170 while (node != NULL) { 1171 if (node->used > 0) 1172 count++; 1173 1174 node = (data_node *)list_get_next_item(&buffer->buffers, node); 1175 } 1176 1177 return count; 1178 } 1179 1180 1181 static void 1182 swap_addresses(net_buffer *buffer) 1183 { 1184 std::swap(buffer->source, buffer->destination); 1185 } 1186 1187 1188 status_t 1189 init_net_buffers() 1190 { 1191 // TODO improve our code a bit so we can add constructors 1192 // and keep around half-constructed buffers in the slab 1193 1194 sNetBufferCache = create_object_cache("net buffer cache", 1195 sizeof(net_buffer_private), 8, NULL, NULL, NULL); 1196 if (sNetBufferCache == NULL) 1197 return B_NO_MEMORY; 1198 1199 sDataNodeCache = create_object_cache("data node cache", BUFFER_SIZE, 0, 1200 NULL, NULL, NULL); 1201 if (sDataNodeCache == NULL) { 1202 delete_object_cache(sNetBufferCache); 1203 return B_NO_MEMORY; 1204 } 1205 1206 return B_OK; 1207 } 1208 1209 1210 status_t 1211 uninit_net_buffers() 1212 { 1213 delete_object_cache(sNetBufferCache); 1214 delete_object_cache(sDataNodeCache); 1215 1216 return B_OK; 1217 } 1218 1219 1220 static status_t 1221 std_ops(int32 op, ...) 1222 { 1223 switch (op) { 1224 case B_MODULE_INIT: 1225 case B_MODULE_UNINIT: 1226 return B_OK; 1227 1228 default: 1229 return B_ERROR; 1230 } 1231 } 1232 1233 1234 net_buffer_module_info gNetBufferModule = { 1235 { 1236 NET_BUFFER_MODULE_NAME, 1237 0, 1238 std_ops 1239 }, 1240 create_buffer, 1241 free_buffer, 1242 1243 duplicate_buffer, 1244 clone_buffer, 1245 split_buffer, 1246 merge_buffer, 1247 1248 prepend_size, 1249 prepend_data, 1250 append_size, 1251 append_data, 1252 NULL, // insert 1253 NULL, // remove 1254 remove_header, 1255 remove_trailer, 1256 trim_data, 1257 append_cloned_data, 1258 1259 NULL, // associate_data 1260 1261 direct_access, 1262 read_data, 1263 write_data, 1264 1265 checksum_data, 1266 1267 NULL, // get_memory_map 1268 get_iovecs, 1269 count_iovecs, 1270 1271 swap_addresses, 1272 1273 dump_buffer, // dump 1274 }; 1275 1276