2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
10 #include "simple_net_buffer.h"
14 #include <net_buffer.h>
15 #include <slab/Slab.h>
17 #include <util/list.h>
19 #include <ByteOrder.h>
21 #include <KernelExport.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
30 #include "paranoia_config.h"
33 //#define TRACE_BUFFER
35 # define TRACE(x) dprintf x
41 #define MAX_ANCILLARY_DATA_SIZE 128
43 struct ancillary_data
: DoublyLinkedListLinkImpl
<ancillary_data
> {
46 return (char*)this + _ALIGN(sizeof(ancillary_data
));
49 static ancillary_data
* FromData(void* data
)
51 return (ancillary_data
*)((char*)data
- _ALIGN(sizeof(ancillary_data
)));
54 ancillary_data_header header
;
55 void (*destructor
)(const ancillary_data_header
*, void*);
58 typedef DoublyLinkedList
<ancillary_data
> ancillary_data_list
;
61 struct net_buffer_private
: simple_net_buffer
{
62 ancillary_data_list ancillary_data
;
66 static status_t
append_data(net_buffer
*buffer
, const void *data
, size_t size
);
67 static status_t
trim_data(net_buffer
*_buffer
, size_t newSize
);
68 static status_t
remove_header(net_buffer
*_buffer
, size_t bytes
);
69 static status_t
remove_trailer(net_buffer
*_buffer
, size_t bytes
);
73 copy_metadata(net_buffer
*destination
, const net_buffer
*source
)
75 memcpy(destination
->source
, source
->source
,
76 min_c(source
->source
->sa_len
, sizeof(sockaddr_storage
)));
77 memcpy(destination
->destination
, source
->destination
,
78 min_c(source
->destination
->sa_len
, sizeof(sockaddr_storage
)));
80 destination
->flags
= source
->flags
;
81 destination
->interface
= source
->interface
;
82 destination
->offset
= source
->offset
;
83 destination
->size
= source
->size
;
84 destination
->protocol
= source
->protocol
;
85 destination
->type
= source
->type
;
89 // #pragma mark - module API
93 create_buffer(size_t headerSpace
)
95 net_buffer_private
*buffer
= new(nothrow
) net_buffer_private
;
99 TRACE(("%ld: create buffer %p\n", find_thread(NULL
), buffer
));
102 new(&buffer
->ancillary_data
) ancillary_data_list
;
104 buffer
->source
= (sockaddr
*)&buffer
->storage
.source
;
105 buffer
->destination
= (sockaddr
*)&buffer
->storage
.destination
;
107 buffer
->storage
.source
.ss_len
= 0;
108 buffer
->storage
.destination
.ss_len
= 0;
110 buffer
->interface
= NULL
;
122 free_buffer(net_buffer
*_buffer
)
124 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
131 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal
132 storage; they are completely independent from each other.
135 duplicate_buffer(net_buffer
*_buffer
)
137 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
139 net_buffer
* duplicate
= create_buffer(0);
140 if (duplicate
== NULL
)
143 if (append_data(duplicate
, buffer
->data
, buffer
->size
) != B_OK
) {
144 free_buffer(duplicate
);
148 copy_metadata(duplicate
, buffer
);
154 /*! Clones the buffer by grabbing another reference to the underlying data.
155 If that data changes, it will be changed in the clone as well.
157 If \a shareFreeSpace is \c true, the cloned buffer may claim the free
158 space in the original buffer as the original buffer can still do. If you
159 are using this, it's your responsibility that only one of the buffers
163 clone_buffer(net_buffer
*_buffer
, bool shareFreeSpace
)
165 return duplicate_buffer(_buffer
);
170 Split the buffer at offset, the header data
171 is returned as new buffer.
172 TODO: optimize and avoid making a copy.
175 split_buffer(net_buffer
*_from
, uint32 offset
)
177 net_buffer_private
*from
= (net_buffer_private
*)_from
;
179 if (offset
> from
->size
)
182 net_buffer_private
* buffer
= (net_buffer_private
*)create_buffer(0);
186 // allocate space for the tail data
187 size_t remaining
= from
->size
- offset
;
188 uint8
* tailData
= (uint8
*)malloc(remaining
);
189 if (tailData
== NULL
) {
194 memcpy(tailData
, from
->data
+ offset
, remaining
);
196 // truncate original data and move it to the new buffer
197 buffer
->data
= (uint8
*)realloc(from
->data
, offset
);
198 buffer
->size
= offset
;
200 // the old buffer gets the newly allocated tail data
201 from
->data
= tailData
;
202 from
->size
= remaining
;
209 Merges the second buffer with the first. If \a after is \c true, the
210 second buffer's contents will be appended to the first ones, else they
212 The second buffer will be freed if this function succeeds.
215 merge_buffer(net_buffer
*_buffer
, net_buffer
*_with
, bool after
)
217 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
218 net_buffer_private
*with
= (net_buffer_private
*)_with
;
223 // the simple case: just append the second buffer
224 status_t error
= append_data(buffer
, with
->data
, with
->size
);
228 // append buffer to the second buffer, then switch the data
229 status_t error
= append_data(with
, buffer
->data
, buffer
->size
);
234 buffer
->data
= with
->data
;
235 buffer
->size
= with
->size
;
246 /*! Writes into existing allocated memory.
247 \return B_BAD_VALUE if you write outside of the buffers current
251 write_data(net_buffer
*_buffer
, size_t offset
, const void *data
, size_t size
)
253 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
255 if (offset
+ size
> buffer
->size
)
260 memcpy(buffer
->data
+ offset
, data
, size
);
267 read_data(net_buffer
*_buffer
, size_t offset
, void *data
, size_t size
)
269 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
271 if (offset
+ size
> buffer
->size
)
276 memcpy(data
, buffer
->data
+ offset
, size
);
283 prepend_size(net_buffer
*_buffer
, size_t size
, void **_contiguousBuffer
)
288 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
290 uint8
* newData
= (uint8
*)malloc(buffer
->size
+ size
);
294 memcpy(newData
+ size
, buffer
->data
, buffer
->size
);
297 buffer
->data
= newData
;
298 buffer
->size
+= size
;
300 if (_contiguousBuffer
!= NULL
)
301 *_contiguousBuffer
= buffer
->data
;
308 prepend_data(net_buffer
*buffer
, const void *data
, size_t size
)
310 status_t status
= prepend_size(buffer
, size
, NULL
);
314 write_data(buffer
, 0, data
, size
);
321 append_size(net_buffer
*_buffer
, size_t size
, void **_contiguousBuffer
)
326 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
328 uint8
* newData
= (uint8
*)realloc(buffer
->data
, buffer
->size
+ size
);
332 if (_contiguousBuffer
!= NULL
)
333 *_contiguousBuffer
= newData
+ buffer
->size
;
335 buffer
->data
= newData
;
336 buffer
->size
+= size
;
343 append_data(net_buffer
*buffer
, const void *data
, size_t size
)
345 size_t used
= buffer
->size
;
347 status_t status
= append_size(buffer
, size
, NULL
);
351 write_data(buffer
, used
, data
, size
);
358 Removes bytes from the beginning of the buffer.
361 remove_header(net_buffer
*_buffer
, size_t bytes
)
363 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
365 if (bytes
> buffer
->size
)
370 buffer
->size
-= bytes
;
371 memmove(buffer
->data
, buffer
->data
+ bytes
, buffer
->size
);
372 buffer
->data
= (uint8
*)realloc(buffer
->data
, buffer
->size
);
379 Removes bytes from the end of the buffer.
382 remove_trailer(net_buffer
*buffer
, size_t bytes
)
384 return trim_data(buffer
, buffer
->size
- bytes
);
389 Trims the buffer to the specified \a newSize by removing space from
390 the end of the buffer.
393 trim_data(net_buffer
*_buffer
, size_t newSize
)
395 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
397 if (newSize
> buffer
->size
)
399 if (newSize
== buffer
->size
)
402 buffer
->data
= (uint8
*)realloc(buffer
->data
, newSize
);
403 buffer
->size
= newSize
;
410 Appends data coming from buffer \a source to the buffer \a buffer. It only
411 clones the data, though, that is the data is not copied, just referenced.
414 append_cloned_data(net_buffer
*_buffer
, net_buffer
*_source
, uint32 offset
,
420 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
421 net_buffer_private
*source
= (net_buffer_private
*)_source
;
423 if (offset
+ bytes
> source
->size
)
426 return append_data(buffer
, source
->data
+ offset
, bytes
);
431 Attaches ancillary data to the given buffer. The data are completely
432 orthogonal to the data the buffer stores.
434 \param buffer The buffer.
435 \param header Description of the data.
436 \param data If not \c NULL, the data are copied into the allocated storage.
437 \param destructor If not \c NULL, this function will be invoked with the
438 data as parameter when the buffer is destroyed.
439 \param _allocatedData Will be set to the storage allocated for the data.
440 \return \c B_OK when everything goes well, another error code otherwise.
443 attach_ancillary_data(net_buffer
*_buffer
, const ancillary_data_header
*header
,
444 const void *data
, void (*destructor
)(const ancillary_data_header
*, void*),
445 void **_allocatedData
)
447 // TODO: Obviously it would be nice to allocate the memory for the
448 // ancillary data in the buffer.
449 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
455 if (header
->len
> MAX_ANCILLARY_DATA_SIZE
)
459 void *dataBuffer
= malloc(_ALIGN(sizeof(ancillary_data
)) + header
->len
);
460 if (dataBuffer
== NULL
)
463 // init and attach the structure
464 ancillary_data
*ancillaryData
= new(dataBuffer
) ancillary_data
;
465 ancillaryData
->header
= *header
;
466 ancillaryData
->destructor
= destructor
;
468 buffer
->ancillary_data
.Add(ancillaryData
);
471 memcpy(ancillaryData
->Data(), data
, header
->len
);
473 if (_allocatedData
!= NULL
)
474 *_allocatedData
= ancillaryData
->Data();
481 Detaches ancillary data from the given buffer. The associated memory is
482 free, i.e. the \a data pointer must no longer be used after calling this
483 function. Depending on \a destroy, the destructor is invoked before freeing
486 \param buffer The buffer.
487 \param data Pointer to the data to be removed (as returned by
488 attach_ancillary_data() or next_ancillary_data()).
489 \param destroy If \c true, the destructor, if one was passed to
490 attach_ancillary_data(), is invoked for the data.
491 \return \c B_OK when everything goes well, another error code otherwise.
494 detach_ancillary_data(net_buffer
*_buffer
, void *data
, bool destroy
)
496 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
501 ancillary_data
*ancillaryData
= ancillary_data::FromData(data
);
503 buffer
->ancillary_data
.Remove(ancillaryData
);
505 if (destroy
&& ancillaryData
->destructor
!= NULL
) {
506 ancillaryData
->destructor(&ancillaryData
->header
,
507 ancillaryData
->Data());
517 Moves all ancillary data from buffer \c from to the end of the list of
518 ancillary data of buffer \c to. Note, that this is the only function that
519 transfers or copies ancillary data from one buffer to another.
521 \param from The buffer from which to remove the ancillary data.
522 \param to The buffer to which to add teh ancillary data.
523 \return A pointer to the first of the moved ancillary data, if any, \c NULL
527 transfer_ancillary_data(net_buffer
*_from
, net_buffer
*_to
)
529 net_buffer_private
*from
= (net_buffer_private
*)_from
;
530 net_buffer_private
*to
= (net_buffer_private
*)_to
;
532 if (from
== NULL
|| to
== NULL
)
535 ancillary_data
*ancillaryData
= from
->ancillary_data
.Head();
536 to
->ancillary_data
.MoveFrom(&from
->ancillary_data
);
538 return ancillaryData
!= NULL
? ancillaryData
->Data() : NULL
;
543 Returns the next ancillary data. When iterating over the data, initially
544 a \c NULL pointer shall be passed as \a previousData, subsequently the
545 previously returned data pointer. After the last item, \c NULL is returned.
547 Note, that it is not safe to call detach_ancillary_data() for a data item
548 and then pass that pointer to this function. First get the next item, then
549 detach the previous one.
551 \param buffer The buffer.
552 \param previousData The pointer to the previous data returned by this
553 function. Initially \c NULL shall be passed.
554 \param header Pointer to allocated storage into which the data description
555 is written. May be \c NULL.
556 \return A pointer to the next ancillary data in the buffer. \c NULL after
560 next_ancillary_data(net_buffer
*_buffer
, void *previousData
,
561 ancillary_data_header
*_header
)
563 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
565 ancillary_data
*ancillaryData
;
567 if (previousData
== NULL
) {
568 ancillaryData
= buffer
->ancillary_data
.Head();
570 ancillaryData
= ancillary_data::FromData(previousData
);
571 ancillaryData
= buffer
->ancillary_data
.GetNext(ancillaryData
);
574 if (ancillaryData
== NULL
)
578 *_header
= ancillaryData
->header
;
580 return ancillaryData
->Data();
585 Tries to directly access the requested space in the buffer.
586 If the space is contiguous, the function will succeed and place a pointer
587 to that space into \a _contiguousBuffer.
589 \return B_BAD_VALUE if the offset is outside of the buffer's bounds.
590 \return B_ERROR in case the buffer is not contiguous at that location.
593 direct_access(net_buffer
*_buffer
, uint32 offset
, size_t size
,
594 void **_contiguousBuffer
)
596 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
598 if (offset
+ size
> buffer
->size
)
601 *_contiguousBuffer
= buffer
->data
+ offset
;
607 checksum_data(net_buffer
*_buffer
, uint32 offset
, size_t size
, bool finalize
)
609 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
611 if (offset
+ size
> buffer
->size
|| size
== 0)
614 uint16 sum
= compute_checksum(buffer
->data
+ offset
, size
);
615 if ((offset
& 1) != 0) {
616 // if we're at an uneven offset, we have to swap the checksum
617 sum
= __swap_int16(sum
);
628 get_iovecs(net_buffer
*_buffer
, struct iovec
*iovecs
, uint32 vecCount
)
630 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
632 iovecs
[0].iov_base
= buffer
->data
;
633 iovecs
[0].iov_len
= buffer
->size
;
640 count_iovecs(net_buffer
*_buffer
)
647 swap_addresses(net_buffer
*buffer
)
649 std::swap(buffer
->source
, buffer
->destination
);
654 dump_buffer(net_buffer
*_buffer
)
656 net_buffer_private
*buffer
= (net_buffer_private
*)_buffer
;
658 dprintf("buffer %p, size %ld, data: %p\n", buffer
, buffer
->size
,
660 dump_block((char*)buffer
->data
, min_c(buffer
->size
, 32), " ");
665 std_ops(int32 op
, ...)
671 case B_MODULE_UNINIT
:
680 net_buffer_module_info gSimpleNetBufferModule
= {
681 //net_buffer_module_info gNetBufferModule = {
683 NET_BUFFER_MODULE_NAME
,
706 NULL
, // associate_data
708 attach_ancillary_data
,
709 detach_ancillary_data
,
710 transfer_ancillary_data
,
719 NULL
, // get_memory_map