1 /*
2 * Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 * Ingo Weinhold, ingo_weinhold@gmx.de
8 */
9
10 #include "simple_net_buffer.h"
11
12 #include "utility.h"
13
14 #include <net_buffer.h>
15 #include <slab/Slab.h>
16 #include <tracing.h>
17 #include <util/list.h>
18
19 #include <ByteOrder.h>
20 #include <debug.h>
21 #include <KernelExport.h>
22 #include <util/AutoLock.h>
23 #include <util/DoublyLinkedList.h>
24
25 #include <algorithm>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/uio.h>
29
30 #include "paranoia_config.h"
31
32
33 //#define TRACE_BUFFER
34 #ifdef TRACE_BUFFER
35 # define TRACE(x) dprintf x
36 #else
37 # define TRACE(x) ;
38 #endif
39
40
41 #define MAX_ANCILLARY_DATA_SIZE 128
42
43 struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
Dataancillary_data44 void* Data()
45 {
46 return (char*)this + _ALIGN(sizeof(ancillary_data));
47 }
48
FromDataancillary_data49 static ancillary_data* FromData(void* data)
50 {
51 return (ancillary_data*)((char*)data - _ALIGN(sizeof(ancillary_data)));
52 }
53
54 ancillary_data_header header;
55 void (*destructor)(const ancillary_data_header*, void*);
56 };
57
58 typedef DoublyLinkedList<ancillary_data> ancillary_data_list;
59
60
61 struct net_buffer_private : simple_net_buffer {
62 ancillary_data_list ancillary_data;
63 };
64
65
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);
70
71
72 static void
copy_metadata(net_buffer * destination,const net_buffer * source)73 copy_metadata(net_buffer *destination, const net_buffer *source)
74 {
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)));
79
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;
86 }
87
88
89 // #pragma mark - module API
90
91
92 static net_buffer *
create_buffer(size_t headerSpace)93 create_buffer(size_t headerSpace)
94 {
95 net_buffer_private *buffer = new(nothrow) net_buffer_private;
96 if (buffer == NULL)
97 return NULL;
98
99 TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
100
101 buffer->data = NULL;
102 new(&buffer->ancillary_data) ancillary_data_list;
103
104 buffer->source = (sockaddr *)&buffer->storage.source;
105 buffer->destination = (sockaddr *)&buffer->storage.destination;
106
107 buffer->storage.source.ss_len = 0;
108 buffer->storage.destination.ss_len = 0;
109
110 buffer->interface = NULL;
111 buffer->offset = 0;
112 buffer->flags = 0;
113 buffer->size = 0;
114
115 buffer->type = -1;
116
117 return buffer;
118 }
119
120
121 static void
free_buffer(net_buffer * _buffer)122 free_buffer(net_buffer *_buffer)
123 {
124 net_buffer_private *buffer = (net_buffer_private *)_buffer;
125
126 free(buffer->data);
127 delete buffer;
128 }
129
130
131 /*! Creates a duplicate of the \a buffer. The new buffer does not share internal
132 storage; they are completely independent from each other.
133 */
134 static net_buffer *
duplicate_buffer(net_buffer * _buffer)135 duplicate_buffer(net_buffer *_buffer)
136 {
137 net_buffer_private *buffer = (net_buffer_private *)_buffer;
138
139 net_buffer* duplicate = create_buffer(0);
140 if (duplicate == NULL)
141 return NULL;
142
143 if (append_data(duplicate, buffer->data, buffer->size) != B_OK) {
144 free_buffer(duplicate);
145 return NULL;
146 }
147
148 copy_metadata(duplicate, buffer);
149
150 return duplicate;
151 }
152
153
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.
156
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.
161 */
162 static net_buffer *
clone_buffer(net_buffer * _buffer,bool shareFreeSpace)163 clone_buffer(net_buffer *_buffer, bool shareFreeSpace)
164 {
165 return duplicate_buffer(_buffer);
166 }
167
168
169 /*!
170 Split the buffer at offset, the header data
171 is returned as new buffer.
172 TODO: optimize and avoid making a copy.
173 */
174 static net_buffer *
split_buffer(net_buffer * _from,uint32 offset)175 split_buffer(net_buffer *_from, uint32 offset)
176 {
177 net_buffer_private *from = (net_buffer_private *)_from;
178
179 if (offset > from->size)
180 return NULL;
181
182 net_buffer_private* buffer = (net_buffer_private*)create_buffer(0);
183 if (buffer == NULL)
184 return NULL;
185
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;
192 }
193
194 memcpy(tailData, from->data + offset, remaining);
195
196 // truncate original data and move it to the new buffer
197 buffer->data = (uint8*)realloc(from->data, offset);
198 buffer->size = offset;
199
200 // the old buffer gets the newly allocated tail data
201 from->data = tailData;
202 from->size = remaining;
203
204 return buffer;
205 }
206
207
208 /*!
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.
213 */
214 static status_t
merge_buffer(net_buffer * _buffer,net_buffer * _with,bool after)215 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
216 {
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;
221
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;
232
233 free(buffer->data);
234 buffer->data = with->data;
235 buffer->size = with->size;
236
237 with->data = NULL;
238 }
239
240 free_buffer(with);
241
242 return B_OK;
243 }
244
245
246 /*! Writes into existing allocated memory.
247 \return B_BAD_VALUE if you write outside of the buffers current
248 bounds.
249 */
250 static status_t
write_data(net_buffer * _buffer,size_t offset,const void * data,size_t size)251 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size)
252 {
253 net_buffer_private *buffer = (net_buffer_private *)_buffer;
254
255 if (offset + size > buffer->size)
256 return B_BAD_VALUE;
257 if (size == 0)
258 return B_OK;
259
260 memcpy(buffer->data + offset, data, size);
261
262 return B_OK;
263 }
264
265
266 static status_t
read_data(net_buffer * _buffer,size_t offset,void * data,size_t size)267 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size)
268 {
269 net_buffer_private *buffer = (net_buffer_private *)_buffer;
270
271 if (offset + size > buffer->size)
272 return B_BAD_VALUE;
273 if (size == 0)
274 return B_OK;
275
276 memcpy(data, buffer->data + offset, size);
277
278 return B_OK;
279 }
280
281
282 static status_t
prepend_size(net_buffer * _buffer,size_t size,void ** _contiguousBuffer)283 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
284 {
285 if (size == 0)
286 return B_OK;
287
288 net_buffer_private *buffer = (net_buffer_private *)_buffer;
289
290 uint8* newData = (uint8*)malloc(buffer->size + size);
291 if (newData == NULL)
292 return B_NO_MEMORY;
293
294 memcpy(newData + size, buffer->data, buffer->size);
295
296 free(buffer->data);
297 buffer->data = newData;
298 buffer->size += size;
299
300 if (_contiguousBuffer != NULL)
301 *_contiguousBuffer = buffer->data;
302
303 return B_OK;
304 }
305
306
307 static status_t
prepend_data(net_buffer * buffer,const void * data,size_t size)308 prepend_data(net_buffer *buffer, const void *data, size_t size)
309 {
310 status_t status = prepend_size(buffer, size, NULL);
311 if (status < B_OK)
312 return status;
313
314 write_data(buffer, 0, data, size);
315
316 return B_OK;
317 }
318
319
320 static status_t
append_size(net_buffer * _buffer,size_t size,void ** _contiguousBuffer)321 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
322 {
323 if (size == 0)
324 return B_OK;
325
326 net_buffer_private *buffer = (net_buffer_private *)_buffer;
327
328 uint8* newData = (uint8*)realloc(buffer->data, buffer->size + size);
329 if (newData == NULL)
330 return B_NO_MEMORY;
331
332 if (_contiguousBuffer != NULL)
333 *_contiguousBuffer = newData + buffer->size;
334
335 buffer->data = newData;
336 buffer->size += size;
337
338 return B_OK;
339 }
340
341
342 static status_t
append_data(net_buffer * buffer,const void * data,size_t size)343 append_data(net_buffer *buffer, const void *data, size_t size)
344 {
345 size_t used = buffer->size;
346
347 status_t status = append_size(buffer, size, NULL);
348 if (status < B_OK)
349 return status;
350
351 write_data(buffer, used, data, size);
352
353 return B_OK;
354 }
355
356
357 /*!
358 Removes bytes from the beginning of the buffer.
359 */
360 static status_t
remove_header(net_buffer * _buffer,size_t bytes)361 remove_header(net_buffer *_buffer, size_t bytes)
362 {
363 net_buffer_private *buffer = (net_buffer_private *)_buffer;
364
365 if (bytes > buffer->size)
366 return B_BAD_VALUE;
367 if (bytes == 0)
368 return B_OK;
369
370 buffer->size -= bytes;
371 memmove(buffer->data, buffer->data + bytes, buffer->size);
372 buffer->data = (uint8*)realloc(buffer->data, buffer->size);
373
374 return B_OK;
375 }
376
377
378 /*!
379 Removes bytes from the end of the buffer.
380 */
381 static status_t
remove_trailer(net_buffer * buffer,size_t bytes)382 remove_trailer(net_buffer *buffer, size_t bytes)
383 {
384 return trim_data(buffer, buffer->size - bytes);
385 }
386
387
388 /*!
389 Trims the buffer to the specified \a newSize by removing space from
390 the end of the buffer.
391 */
392 static status_t
trim_data(net_buffer * _buffer,size_t newSize)393 trim_data(net_buffer *_buffer, size_t newSize)
394 {
395 net_buffer_private *buffer = (net_buffer_private *)_buffer;
396
397 if (newSize > buffer->size)
398 return B_BAD_VALUE;
399 if (newSize == buffer->size)
400 return B_OK;
401
402 buffer->data = (uint8*)realloc(buffer->data, newSize);
403 buffer->size = newSize;
404
405 return B_OK;
406 }
407
408
409 /*!
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.
412 */
413 static status_t
append_cloned_data(net_buffer * _buffer,net_buffer * _source,uint32 offset,size_t bytes)414 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
415 size_t bytes)
416 {
417 if (bytes == 0)
418 return B_OK;
419
420 net_buffer_private *buffer = (net_buffer_private *)_buffer;
421 net_buffer_private *source = (net_buffer_private *)_source;
422
423 if (offset + bytes > source->size)
424 return B_BAD_VALUE;
425
426 return append_data(buffer, source->data + offset, bytes);
427 }
428
429
430 /*!
431 Attaches ancillary data to the given buffer. The data are completely
432 orthogonal to the data the buffer stores.
433
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.
441 */
442 static status_t
attach_ancillary_data(net_buffer * _buffer,const ancillary_data_header * header,const void * data,void (* destructor)(const ancillary_data_header *,void *),void ** _allocatedData)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)
446 {
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;
450
451 // check parameters
452 if (header == NULL)
453 return B_BAD_VALUE;
454
455 if (header->len > MAX_ANCILLARY_DATA_SIZE)
456 return ENOBUFS;
457
458 // allocate buffer
459 void *dataBuffer = malloc(_ALIGN(sizeof(ancillary_data)) + header->len);
460 if (dataBuffer == NULL)
461 return B_NO_MEMORY;
462
463 // init and attach the structure
464 ancillary_data *ancillaryData = new(dataBuffer) ancillary_data;
465 ancillaryData->header = *header;
466 ancillaryData->destructor = destructor;
467
468 buffer->ancillary_data.Add(ancillaryData);
469
470 if (data != NULL)
471 memcpy(ancillaryData->Data(), data, header->len);
472
473 if (_allocatedData != NULL)
474 *_allocatedData = ancillaryData->Data();
475
476 return B_OK;
477 }
478
479
480 /*!
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.
485
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.
492 */
493 static status_t
detach_ancillary_data(net_buffer * _buffer,void * data,bool destroy)494 detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
495 {
496 net_buffer_private *buffer = (net_buffer_private *)_buffer;
497
498 if (data == NULL)
499 return B_BAD_VALUE;
500
501 ancillary_data *ancillaryData = ancillary_data::FromData(data);
502
503 buffer->ancillary_data.Remove(ancillaryData);
504
505 if (destroy && ancillaryData->destructor != NULL) {
506 ancillaryData->destructor(&ancillaryData->header,
507 ancillaryData->Data());
508 }
509
510 free(ancillaryData);
511
512 return B_OK;
513 }
514
515
516 /*!
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.
520
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.
525 */
526 static void *
transfer_ancillary_data(net_buffer * _from,net_buffer * _to)527 transfer_ancillary_data(net_buffer *_from, net_buffer *_to)
528 {
529 net_buffer_private *from = (net_buffer_private *)_from;
530 net_buffer_private *to = (net_buffer_private *)_to;
531
532 if (from == NULL || to == NULL)
533 return NULL;
534
535 ancillary_data *ancillaryData = from->ancillary_data.Head();
536 to->ancillary_data.MoveFrom(&from->ancillary_data);
537
538 return ancillaryData != NULL ? ancillaryData->Data() : NULL;
539 }
540
541
542 /*!
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.
546
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.
550
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.
558 */
559 static void*
next_ancillary_data(net_buffer * _buffer,void * previousData,ancillary_data_header * _header)560 next_ancillary_data(net_buffer *_buffer, void *previousData,
561 ancillary_data_header *_header)
562 {
563 net_buffer_private *buffer = (net_buffer_private *)_buffer;
564
565 ancillary_data *ancillaryData;
566
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);
572 }
573
574 if (ancillaryData == NULL)
575 return NULL;
576
577 if (_header != NULL)
578 *_header = ancillaryData->header;
579
580 return ancillaryData->Data();
581 }
582
583
584 /*!
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.
588
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.
591 */
592 static status_t
direct_access(net_buffer * _buffer,uint32 offset,size_t size,void ** _contiguousBuffer)593 direct_access(net_buffer *_buffer, uint32 offset, size_t size,
594 void **_contiguousBuffer)
595 {
596 net_buffer_private *buffer = (net_buffer_private *)_buffer;
597
598 if (offset + size > buffer->size)
599 return B_BAD_VALUE;
600
601 *_contiguousBuffer = buffer->data + offset;
602 return B_OK;
603 }
604
605
606 static int32
checksum_data(net_buffer * _buffer,uint32 offset,size_t size,bool finalize)607 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize)
608 {
609 net_buffer_private *buffer = (net_buffer_private *)_buffer;
610
611 if (offset + size > buffer->size || size == 0)
612 return B_BAD_VALUE;
613
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);
618 }
619
620 if (!finalize)
621 return (uint16)sum;
622
623 return (uint16)~sum;
624 }
625
626
627 static uint32
get_iovecs(net_buffer * _buffer,struct iovec * iovecs,uint32 vecCount)628 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount)
629 {
630 net_buffer_private *buffer = (net_buffer_private *)_buffer;
631
632 iovecs[0].iov_base = buffer->data;
633 iovecs[0].iov_len = buffer->size;
634
635 return 1;
636 }
637
638
639 static uint32
count_iovecs(net_buffer * _buffer)640 count_iovecs(net_buffer *_buffer)
641 {
642 return 1;
643 }
644
645
646 static void
swap_addresses(net_buffer * buffer)647 swap_addresses(net_buffer *buffer)
648 {
649 std::swap(buffer->source, buffer->destination);
650 }
651
652
653 static void
dump_buffer(net_buffer * _buffer)654 dump_buffer(net_buffer *_buffer)
655 {
656 net_buffer_private *buffer = (net_buffer_private *)_buffer;
657
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), " ");
661 }
662
663
664 static status_t
std_ops(int32 op,...)665 std_ops(int32 op, ...)
666 {
667 switch (op) {
668 case B_MODULE_INIT:
669 return B_OK;
670
671 case B_MODULE_UNINIT:
672 return B_OK;
673
674 default:
675 return B_ERROR;
676 }
677 }
678
679
680 net_buffer_module_info gSimpleNetBufferModule = {
681 //net_buffer_module_info gNetBufferModule = {
682 {
683 NET_BUFFER_MODULE_NAME,
684 0,
685 std_ops
686 },
687 create_buffer,
688 free_buffer,
689
690 duplicate_buffer,
691 clone_buffer,
692 split_buffer,
693 merge_buffer,
694
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,
705
706 NULL, // associate_data
707
708 attach_ancillary_data,
709 detach_ancillary_data,
710 transfer_ancillary_data,
711 next_ancillary_data,
712
713 direct_access,
714 read_data,
715 write_data,
716
717 checksum_data,
718
719 NULL, // get_memory_map
720 get_iovecs,
721 count_iovecs,
722
723 swap_addresses,
724
725 dump_buffer, // dump
726 };
727
728