BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / network / stack / simple_net_buffer.cpp
blob512fa6db93a445d4dff171fb5dc4b228b3adb135
1 /*
2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
8 */
10 #include "simple_net_buffer.h"
12 #include "utility.h"
14 #include <net_buffer.h>
15 #include <slab/Slab.h>
16 #include <tracing.h>
17 #include <util/list.h>
19 #include <ByteOrder.h>
20 #include <debug.h>
21 #include <KernelExport.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
25 #include <algorithm>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/uio.h>
30 #include "paranoia_config.h"
33 //#define TRACE_BUFFER
34 #ifdef TRACE_BUFFER
35 # define TRACE(x) dprintf x
36 #else
37 # define TRACE(x) ;
38 #endif
41 #define MAX_ANCILLARY_DATA_SIZE 128
43 struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
44 void* 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);
72 static void
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
92 static net_buffer *
93 create_buffer(size_t headerSpace)
95 net_buffer_private *buffer = new(nothrow) net_buffer_private;
96 if (buffer == NULL)
97 return NULL;
99 TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
101 buffer->data = NULL;
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;
111 buffer->offset = 0;
112 buffer->flags = 0;
113 buffer->size = 0;
115 buffer->type = -1;
117 return buffer;
121 static void
122 free_buffer(net_buffer *_buffer)
124 net_buffer_private *buffer = (net_buffer_private *)_buffer;
126 free(buffer->data);
127 delete 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.
134 static net_buffer *
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)
141 return NULL;
143 if (append_data(duplicate, buffer->data, buffer->size) != B_OK) {
144 free_buffer(duplicate);
145 return NULL;
148 copy_metadata(duplicate, buffer);
150 return duplicate;
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
160 will do this.
162 static net_buffer *
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.
174 static net_buffer *
175 split_buffer(net_buffer *_from, uint32 offset)
177 net_buffer_private *from = (net_buffer_private *)_from;
179 if (offset > from->size)
180 return NULL;
182 net_buffer_private* buffer = (net_buffer_private*)create_buffer(0);
183 if (buffer == NULL)
184 return NULL;
186 // allocate space for the tail data
187 size_t remaining = from->size - offset;
188 uint8* tailData = (uint8*)malloc(remaining);
189 if (tailData == NULL) {
190 free_buffer(buffer);
191 return 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;
204 return buffer;
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
211 will be prepended.
212 The second buffer will be freed if this function succeeds.
214 static status_t
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;
219 if (with == NULL)
220 return B_BAD_VALUE;
222 if (after) {
223 // the simple case: just append the second buffer
224 status_t error = append_data(buffer, with->data, with->size);
225 if (error != B_OK)
226 return error;
227 } else {
228 // append buffer to the second buffer, then switch the data
229 status_t error = append_data(with, buffer->data, buffer->size);
230 if (error != B_OK)
231 return error;
233 free(buffer->data);
234 buffer->data = with->data;
235 buffer->size = with->size;
237 with->data = NULL;
240 free_buffer(with);
242 return B_OK;
246 /*! Writes into existing allocated memory.
247 \return B_BAD_VALUE if you write outside of the buffers current
248 bounds.
250 static status_t
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)
256 return B_BAD_VALUE;
257 if (size == 0)
258 return B_OK;
260 memcpy(buffer->data + offset, data, size);
262 return B_OK;
266 static status_t
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)
272 return B_BAD_VALUE;
273 if (size == 0)
274 return B_OK;
276 memcpy(data, buffer->data + offset, size);
278 return B_OK;
282 static status_t
283 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
285 if (size == 0)
286 return B_OK;
288 net_buffer_private *buffer = (net_buffer_private *)_buffer;
290 uint8* newData = (uint8*)malloc(buffer->size + size);
291 if (newData == NULL)
292 return B_NO_MEMORY;
294 memcpy(newData + size, buffer->data, buffer->size);
296 free(buffer->data);
297 buffer->data = newData;
298 buffer->size += size;
300 if (_contiguousBuffer != NULL)
301 *_contiguousBuffer = buffer->data;
303 return B_OK;
307 static status_t
308 prepend_data(net_buffer *buffer, const void *data, size_t size)
310 status_t status = prepend_size(buffer, size, NULL);
311 if (status < B_OK)
312 return status;
314 write_data(buffer, 0, data, size);
316 return B_OK;
320 static status_t
321 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
323 if (size == 0)
324 return B_OK;
326 net_buffer_private *buffer = (net_buffer_private *)_buffer;
328 uint8* newData = (uint8*)realloc(buffer->data, buffer->size + size);
329 if (newData == NULL)
330 return B_NO_MEMORY;
332 if (_contiguousBuffer != NULL)
333 *_contiguousBuffer = newData + buffer->size;
335 buffer->data = newData;
336 buffer->size += size;
338 return B_OK;
342 static status_t
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);
348 if (status < B_OK)
349 return status;
351 write_data(buffer, used, data, size);
353 return B_OK;
358 Removes bytes from the beginning of the buffer.
360 static status_t
361 remove_header(net_buffer *_buffer, size_t bytes)
363 net_buffer_private *buffer = (net_buffer_private *)_buffer;
365 if (bytes > buffer->size)
366 return B_BAD_VALUE;
367 if (bytes == 0)
368 return B_OK;
370 buffer->size -= bytes;
371 memmove(buffer->data, buffer->data + bytes, buffer->size);
372 buffer->data = (uint8*)realloc(buffer->data, buffer->size);
374 return B_OK;
379 Removes bytes from the end of the buffer.
381 static status_t
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.
392 static status_t
393 trim_data(net_buffer *_buffer, size_t newSize)
395 net_buffer_private *buffer = (net_buffer_private *)_buffer;
397 if (newSize > buffer->size)
398 return B_BAD_VALUE;
399 if (newSize == buffer->size)
400 return B_OK;
402 buffer->data = (uint8*)realloc(buffer->data, newSize);
403 buffer->size = newSize;
405 return B_OK;
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.
413 static status_t
414 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
415 size_t bytes)
417 if (bytes == 0)
418 return B_OK;
420 net_buffer_private *buffer = (net_buffer_private *)_buffer;
421 net_buffer_private *source = (net_buffer_private *)_source;
423 if (offset + bytes > source->size)
424 return B_BAD_VALUE;
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.
442 static status_t
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;
451 // check parameters
452 if (header == NULL)
453 return B_BAD_VALUE;
455 if (header->len > MAX_ANCILLARY_DATA_SIZE)
456 return ENOBUFS;
458 // allocate buffer
459 void *dataBuffer = malloc(_ALIGN(sizeof(ancillary_data)) + header->len);
460 if (dataBuffer == NULL)
461 return B_NO_MEMORY;
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);
470 if (data != NULL)
471 memcpy(ancillaryData->Data(), data, header->len);
473 if (_allocatedData != NULL)
474 *_allocatedData = ancillaryData->Data();
476 return B_OK;
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
484 the data.
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.
493 static status_t
494 detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
496 net_buffer_private *buffer = (net_buffer_private *)_buffer;
498 if (data == NULL)
499 return B_BAD_VALUE;
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());
510 free(ancillaryData);
512 return B_OK;
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
524 otherwise.
526 static void *
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)
533 return 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
557 the last one.
559 static void*
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();
569 } else {
570 ancillaryData = ancillary_data::FromData(previousData);
571 ancillaryData = buffer->ancillary_data.GetNext(ancillaryData);
574 if (ancillaryData == NULL)
575 return NULL;
577 if (_header != 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.
592 static status_t
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)
599 return B_BAD_VALUE;
601 *_contiguousBuffer = buffer->data + offset;
602 return B_OK;
606 static int32
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)
612 return B_BAD_VALUE;
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);
620 if (!finalize)
621 return (uint16)sum;
623 return (uint16)~sum;
627 static uint32
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;
635 return 1;
639 static uint32
640 count_iovecs(net_buffer *_buffer)
642 return 1;
646 static void
647 swap_addresses(net_buffer *buffer)
649 std::swap(buffer->source, buffer->destination);
653 static void
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,
659 buffer->data);
660 dump_block((char*)buffer->data, min_c(buffer->size, 32), " ");
664 static status_t
665 std_ops(int32 op, ...)
667 switch (op) {
668 case B_MODULE_INIT:
669 return B_OK;
671 case B_MODULE_UNINIT:
672 return B_OK;
674 default:
675 return B_ERROR;
680 net_buffer_module_info gSimpleNetBufferModule = {
681 //net_buffer_module_info gNetBufferModule = {
683 NET_BUFFER_MODULE_NAME,
685 std_ops
687 create_buffer,
688 free_buffer,
690 duplicate_buffer,
691 clone_buffer,
692 split_buffer,
693 merge_buffer,
695 prepend_size,
696 prepend_data,
697 append_size,
698 append_data,
699 NULL, // insert
700 NULL, // remove
701 remove_header,
702 remove_trailer,
703 trim_data,
704 append_cloned_data,
706 NULL, // associate_data
708 attach_ancillary_data,
709 detach_ancillary_data,
710 transfer_ancillary_data,
711 next_ancillary_data,
713 direct_access,
714 read_data,
715 write_data,
717 checksum_data,
719 NULL, // get_memory_map
720 get_iovecs,
721 count_iovecs,
723 swap_addresses,
725 dump_buffer, // dump