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
43struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
44	void* Data()
45	{
46		return (char*)this + _ALIGN(sizeof(ancillary_data));
47	}
48
49	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
58typedef DoublyLinkedList<ancillary_data> ancillary_data_list;
59
60
61struct net_buffer_private : simple_net_buffer {
62	ancillary_data_list	ancillary_data;
63};
64
65
66static status_t append_data(net_buffer *buffer, const void *data, size_t size);
67static status_t trim_data(net_buffer *_buffer, size_t newSize);
68static status_t remove_header(net_buffer *_buffer, size_t bytes);
69static status_t remove_trailer(net_buffer *_buffer, size_t bytes);
70
71
72static void
73copy_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
92static net_buffer *
93create_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
121static void
122free_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*/
134static net_buffer *
135duplicate_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*/
162static net_buffer *
163clone_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*/
174static net_buffer *
175split_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*/
214static status_t
215merge_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*/
250static status_t
251write_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
266static status_t
267read_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
282static status_t
283prepend_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
307static status_t
308prepend_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
320static status_t
321append_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
342static status_t
343append_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*/
360static status_t
361remove_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*/
381static status_t
382remove_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*/
392static status_t
393trim_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*/
413static status_t
414append_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*/
442static status_t
443attach_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*/
493static status_t
494detach_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*/
526static void *
527transfer_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*/
559static void*
560next_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*/
592static status_t
593direct_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
606static int32
607checksum_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
627static uint32
628get_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
639static uint32
640count_iovecs(net_buffer *_buffer)
641{
642	return 1;
643}
644
645
646static void
647swap_addresses(net_buffer *buffer)
648{
649	std::swap(buffer->source, buffer->destination);
650}
651
652
653static void
654dump_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
664static status_t
665std_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
680net_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