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