xref: /haiku/src/add-ons/kernel/network/stack/net_buffer.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 "utility.h"
11 
12 #include <net_buffer.h>
13 #include <slab/Slab.h>
14 #include <tracing.h>
15 #include <util/list.h>
16 
17 #include <ByteOrder.h>
18 #include <debug.h>
19 #include <KernelExport.h>
20 #include <util/DoublyLinkedList.h>
21 
22 #include <algorithm>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/param.h>
26 #include <sys/uio.h>
27 
28 #include "ancillary_data.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 #define BUFFER_SIZE 2048
41 	// maximum implementation derived buffer size is 65536
42 
43 //#define ENABLE_DEBUGGER_COMMANDS	1
44 #define PARANOID_BUFFER_CHECK	NET_BUFFER_PARANOIA
45 
46 #define COMPONENT_PARANOIA_LEVEL	NET_BUFFER_PARANOIA
47 #include <debug_paranoia.h>
48 
49 #define DATA_NODE_READ_ONLY		0x1
50 
51 struct header_space {
52 	uint16	size;
53 	uint16	free;
54 };
55 
56 struct free_data {
57 	struct free_data *next;
58 	uint16		size;
59 };
60 
61 struct data_header {
62 	int32		ref_count;
63 	addr_t		physical_address;
64 	free_data	*first_free;
65 	uint8		*data_end;
66 	header_space	space;
67 	uint16		tail_space;
68 };
69 
70 struct data_node {
71 	struct list_link link;
72 	struct data_header *header;
73 	struct data_header *located;
74 	size_t		offset;			// the net_buffer-wide offset of this node
75 	uint8		*start;			// points to the start of the data
76 	uint16		flags;
77 	uint16		used;			// defines how much memory is used by this node
78 
79 	uint16 HeaderSpace() const
80 	{
81 		if ((flags & DATA_NODE_READ_ONLY) != 0)
82 			return 0;
83 		return header->space.free;
84 	}
85 
86 	void AddHeaderSpace(uint16 toAdd)
87 	{
88 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
89 			header->space.size += toAdd;
90 			header->space.free += toAdd;
91 		}
92 	}
93 
94 	void SubtractHeaderSpace(uint16 toSubtract)
95 	{
96 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
97 			header->space.size -= toSubtract;
98 			header->space.free -= toSubtract;
99 		}
100 	}
101 
102 	uint16 TailSpace() const
103 	{
104 		if ((flags & DATA_NODE_READ_ONLY) != 0)
105 			return 0;
106 		return header->tail_space;
107 	}
108 
109 	void SetTailSpace(uint16 space)
110 	{
111 		if ((flags & DATA_NODE_READ_ONLY) == 0)
112 			header->tail_space = space;
113 	}
114 
115 	void FreeSpace()
116 	{
117 		if ((flags & DATA_NODE_READ_ONLY) == 0) {
118 			uint16 space = used + header->tail_space;
119 			header->space.size += space;
120 			header->space.free += space;
121 			header->tail_space = 0;
122 		}
123 	}
124 };
125 
126 struct net_buffer_private : net_buffer {
127 	struct list			buffers;
128 	data_header			*allocation_header;	// the current place where we
129 											// allocate header space (nodes,...)
130 	ancillary_data_container*	ancillary_data;
131 
132 	struct {
133 		struct sockaddr_storage source;
134 		struct sockaddr_storage destination;
135 	} storage;
136 };
137 
138 
139 #define DATA_HEADER_SIZE				_ALIGN(sizeof(data_header))
140 #define DATA_NODE_SIZE					_ALIGN(sizeof(data_node))
141 #define MAX_FREE_BUFFER_SIZE			(BUFFER_SIZE - DATA_HEADER_SIZE)
142 
143 
144 static object_cache *sNetBufferCache;
145 static object_cache *sDataNodeCache;
146 
147 
148 static status_t append_data(net_buffer *buffer, const void *data, size_t size);
149 static status_t trim_data(net_buffer *_buffer, size_t newSize);
150 static status_t remove_header(net_buffer *_buffer, size_t bytes);
151 static status_t remove_trailer(net_buffer *_buffer, size_t bytes);
152 static status_t append_cloned_data(net_buffer *_buffer, net_buffer *_source,
153 					uint32 offset, size_t bytes);
154 static status_t read_data(net_buffer *_buffer, size_t offset, void *data,
155 					size_t size);
156 
157 
158 #if ENABLE_DEBUGGER_COMMANDS
159 static vint32 sAllocatedDataHeaderCount = 0;
160 static vint32 sAllocatedNetBufferCount = 0;
161 static vint32 sEverAllocatedDataHeaderCount = 0;
162 static vint32 sEverAllocatedNetBufferCount = 0;
163 #endif
164 
165 
166 #if NET_BUFFER_TRACING
167 
168 
169 namespace NetBufferTracing {
170 
171 
172 class NetBufferTraceEntry : public AbstractTraceEntry {
173 	public:
174 		NetBufferTraceEntry(net_buffer* buffer)
175 			:
176 			fBuffer(buffer)
177 		{
178 #if NET_BUFFER_TRACING_STACK_TRACE
179 		fStackTrace = capture_tracing_stack_trace(
180 			NET_BUFFER_TRACING_STACK_TRACE, 0, false);
181 #endif
182 		}
183 
184 #if NET_BUFFER_TRACING_STACK_TRACE
185 		virtual void DumpStackTrace(TraceOutput& out)
186 		{
187 			out.PrintStackTrace(fStackTrace);
188 		}
189 #endif
190 
191 	protected:
192 		net_buffer*	fBuffer;
193 #if NET_BUFFER_TRACING_STACK_TRACE
194 		tracing_stack_trace* fStackTrace;
195 #endif
196 };
197 
198 
199 class Create : public NetBufferTraceEntry {
200 	public:
201 		Create(size_t headerSpace, net_buffer* buffer)
202 			:
203 			NetBufferTraceEntry(buffer),
204 			fHeaderSpace(headerSpace)
205 		{
206 			Initialized();
207 		}
208 
209 		virtual void AddDump(TraceOutput& out)
210 		{
211 			out.Print("net buffer create: header space: %lu -> buffer: %p",
212 				fHeaderSpace, fBuffer);
213 		}
214 
215 	private:
216 		size_t		fHeaderSpace;
217 };
218 
219 
220 class Free : public NetBufferTraceEntry {
221 	public:
222 		Free(net_buffer* buffer)
223 			:
224 			NetBufferTraceEntry(buffer)
225 		{
226 			Initialized();
227 		}
228 
229 		virtual void AddDump(TraceOutput& out)
230 		{
231 			out.Print("net buffer free: buffer: %p", fBuffer);
232 		}
233 };
234 
235 
236 class Duplicate : public NetBufferTraceEntry {
237 	public:
238 		Duplicate(net_buffer* buffer, net_buffer* clone)
239 			:
240 			NetBufferTraceEntry(buffer),
241 			fClone(clone)
242 		{
243 			Initialized();
244 		}
245 
246 		virtual void AddDump(TraceOutput& out)
247 		{
248 			out.Print("net buffer dup: buffer: %p -> %p", fBuffer, fClone);
249 		}
250 
251 	private:
252 		net_buffer*		fClone;
253 };
254 
255 
256 class Clone : public NetBufferTraceEntry {
257 	public:
258 		Clone(net_buffer* buffer, bool shareFreeSpace, net_buffer* clone)
259 			:
260 			NetBufferTraceEntry(buffer),
261 			fClone(clone),
262 			fShareFreeSpace(shareFreeSpace)
263 		{
264 			Initialized();
265 		}
266 
267 		virtual void AddDump(TraceOutput& out)
268 		{
269 			out.Print("net buffer clone: buffer: %p, share free space: %s "
270 				"-> %p", fBuffer, fShareFreeSpace ? "true" : "false", fClone);
271 		}
272 
273 	private:
274 		net_buffer*		fClone;
275 		bool			fShareFreeSpace;
276 };
277 
278 
279 class Split : public NetBufferTraceEntry {
280 	public:
281 		Split(net_buffer* buffer, uint32 offset, net_buffer* newBuffer)
282 			:
283 			NetBufferTraceEntry(buffer),
284 			fNewBuffer(newBuffer),
285 			fOffset(offset)
286 		{
287 			Initialized();
288 		}
289 
290 		virtual void AddDump(TraceOutput& out)
291 		{
292 			out.Print("net buffer split: buffer: %p, offset: %lu "
293 				"-> %p", fBuffer, fOffset, fNewBuffer);
294 		}
295 
296 	private:
297 		net_buffer*		fNewBuffer;
298 		uint32			fOffset;
299 };
300 
301 
302 class Merge : public NetBufferTraceEntry {
303 	public:
304 		Merge(net_buffer* buffer, net_buffer* otherBuffer, bool after)
305 			:
306 			NetBufferTraceEntry(buffer),
307 			fOtherBuffer(otherBuffer),
308 			fAfter(after)
309 		{
310 			Initialized();
311 		}
312 
313 		virtual void AddDump(TraceOutput& out)
314 		{
315 			out.Print("net buffer merge: buffers: %p + %p, after: %s "
316 				"-> %p", fBuffer, fOtherBuffer, fAfter ? "true" : "false",
317 				fOtherBuffer);
318 		}
319 
320 	private:
321 		net_buffer*		fOtherBuffer;
322 		bool			fAfter;
323 };
324 
325 
326 class AppendCloned : public NetBufferTraceEntry {
327 	public:
328 		AppendCloned(net_buffer* buffer, net_buffer* source, uint32 offset,
329 			size_t size)
330 			:
331 			NetBufferTraceEntry(buffer),
332 			fSource(source),
333 			fOffset(offset),
334 			fSize(size)
335 		{
336 			Initialized();
337 		}
338 
339 		virtual void AddDump(TraceOutput& out)
340 		{
341 			out.Print("net buffer append cloned: buffer: %p, from: %p, "
342 				"offset: %lu, size: %lu", fBuffer, fSource, fOffset, fSize);
343 		}
344 
345 	private:
346 		net_buffer*		fSource;
347 		uint32			fOffset;
348 		size_t			fSize;
349 };
350 
351 
352 class PrependSize : public NetBufferTraceEntry {
353 	public:
354 		PrependSize(net_buffer* buffer, size_t size)
355 			:
356 			NetBufferTraceEntry(buffer),
357 			fSize(size)
358 		{
359 			Initialized();
360 		}
361 
362 		virtual void AddDump(TraceOutput& out)
363 		{
364 			out.Print("net buffer prepend size: buffer: %p, size: %lu", fBuffer,
365 				fSize);
366 		}
367 
368 	private:
369 		size_t			fSize;
370 };
371 
372 
373 class AppendSize : public NetBufferTraceEntry {
374 	public:
375 		AppendSize(net_buffer* buffer, size_t size)
376 			:
377 			NetBufferTraceEntry(buffer),
378 			fSize(size)
379 		{
380 			Initialized();
381 		}
382 
383 		virtual void AddDump(TraceOutput& out)
384 		{
385 			out.Print("net buffer append size: buffer: %p, size: %lu", fBuffer,
386 				fSize);
387 		}
388 
389 	private:
390 		size_t			fSize;
391 };
392 
393 
394 class RemoveHeader : public NetBufferTraceEntry {
395 	public:
396 		RemoveHeader(net_buffer* buffer, size_t size)
397 			:
398 			NetBufferTraceEntry(buffer),
399 			fSize(size)
400 		{
401 			Initialized();
402 		}
403 
404 		virtual void AddDump(TraceOutput& out)
405 		{
406 			out.Print("net buffer remove header: buffer: %p, size: %lu",
407 				fBuffer, fSize);
408 		}
409 
410 	private:
411 		size_t			fSize;
412 };
413 
414 
415 class Trim : public NetBufferTraceEntry {
416 	public:
417 		Trim(net_buffer* buffer, size_t size)
418 			:
419 			NetBufferTraceEntry(buffer),
420 			fSize(size)
421 		{
422 			Initialized();
423 		}
424 
425 		virtual void AddDump(TraceOutput& out)
426 		{
427 			out.Print("net buffer trim: buffer: %p, size: %lu",
428 				fBuffer, fSize);
429 		}
430 
431 	private:
432 		size_t			fSize;
433 };
434 
435 
436 class Read : public NetBufferTraceEntry {
437 	public:
438 		Read(net_buffer* buffer, uint32 offset, void* data, size_t size)
439 			:
440 			NetBufferTraceEntry(buffer),
441 			fData(data),
442 			fOffset(offset),
443 			fSize(size)
444 		{
445 			Initialized();
446 		}
447 
448 		virtual void AddDump(TraceOutput& out)
449 		{
450 			out.Print("net buffer read: buffer: %p, offset: %lu, size: %lu, "
451 				"data: %p", fBuffer, fOffset, fSize, fData);
452 		}
453 
454 	private:
455 		void*			fData;
456 		uint32			fOffset;
457 		size_t			fSize;
458 };
459 
460 
461 class Write : public NetBufferTraceEntry {
462 	public:
463 		Write(net_buffer* buffer, uint32 offset, const void* data, size_t size)
464 			:
465 			NetBufferTraceEntry(buffer),
466 			fData(data),
467 			fOffset(offset),
468 			fSize(size)
469 		{
470 			Initialized();
471 		}
472 
473 		virtual void AddDump(TraceOutput& out)
474 		{
475 			out.Print("net buffer write: buffer: %p, offset: %lu, size: %lu, "
476 				"data: %p", fBuffer, fOffset, fSize, fData);
477 		}
478 
479 	private:
480 		const void*		fData;
481 		uint32			fOffset;
482 		size_t			fSize;
483 };
484 
485 
486 #if NET_BUFFER_TRACING >= 2
487 
488 class DataHeaderTraceEntry : public AbstractTraceEntry {
489 	public:
490 		DataHeaderTraceEntry(data_header* header)
491 			:
492 			fHeader(header)
493 		{
494 		}
495 
496 	protected:
497 		data_header*	fHeader;
498 };
499 
500 
501 class CreateDataHeader : public DataHeaderTraceEntry {
502 	public:
503 		CreateDataHeader(data_header* header)
504 			:
505 			DataHeaderTraceEntry(header)
506 		{
507 			Initialized();
508 		}
509 
510 		virtual void AddDump(TraceOutput& out)
511 		{
512 			out.Print("net buffer data header create:  header: %p", fHeader);
513 		}
514 };
515 
516 
517 class AcquireDataHeader : public DataHeaderTraceEntry {
518 	public:
519 		AcquireDataHeader(data_header* header, int32 refCount)
520 			:
521 			DataHeaderTraceEntry(header),
522 			fRefCount(refCount)
523 		{
524 			Initialized();
525 		}
526 
527 		virtual void AddDump(TraceOutput& out)
528 		{
529 			out.Print("net buffer data header acquire: header: %p "
530 				"-> ref count: %ld", fHeader, fRefCount);
531 		}
532 
533 	private:
534 		int32			fRefCount;
535 };
536 
537 
538 class ReleaseDataHeader : public DataHeaderTraceEntry {
539 	public:
540 		ReleaseDataHeader(data_header* header, int32 refCount)
541 			:
542 			DataHeaderTraceEntry(header),
543 			fRefCount(refCount)
544 		{
545 			Initialized();
546 		}
547 
548 		virtual void AddDump(TraceOutput& out)
549 		{
550 			out.Print("net buffer data header release: header: %p "
551 				"-> ref count: %ld", fHeader, fRefCount);
552 		}
553 
554 	private:
555 		int32			fRefCount;
556 };
557 
558 #	define T2(x)	new(std::nothrow) NetBufferTracing::x
559 #else
560 #	define T2(x)
561 #endif	// NET_BUFFER_TRACING >= 2
562 
563 }	// namespace NetBufferTracing
564 
565 #	define T(x)	new(std::nothrow) NetBufferTracing::x
566 
567 #else
568 #	define T(x)
569 #	define T2(x)
570 #endif	// NET_BUFFER_TRACING
571 
572 
573 #if 1
574 static void
575 dump_buffer(net_buffer *_buffer)
576 {
577 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
578 
579 	dprintf("buffer %p, size %ld\n", buffer, buffer->size);
580 	data_node *node = NULL;
581 	while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) {
582 		dprintf("  node %p, offset %lu, used %u, header %u, tail %u, header %p\n",
583 			node, node->offset, node->used, node->HeaderSpace(), node->TailSpace(), node->header);
584 		//dump_block((char *)node->start, node->used, "    ");
585 		dump_block((char *)node->start, min_c(node->used, 32), "    ");
586 	}
587 }
588 #endif
589 
590 
591 #if ENABLE_DEBUGGER_COMMANDS
592 
593 static int
594 dump_net_buffer_stats(int argc, char** argv)
595 {
596 	kprintf("allocated data headers: %7ld / %7ld\n", sAllocatedDataHeaderCount,
597 		sEverAllocatedDataHeaderCount);
598 	kprintf("allocated net buffers:  %7ld / %7ld\n", sAllocatedNetBufferCount,
599 		sEverAllocatedNetBufferCount);
600 	return 0;
601 }
602 
603 #endif	// ENABLE_DEBUGGER_COMMANDS
604 
605 
606 #if PARANOID_BUFFER_CHECK
607 
608 static void
609 check_buffer(net_buffer *_buffer)
610 {
611 	net_buffer_private *buffer = (net_buffer_private*)_buffer;
612 
613 	// sum up the size of all nodes
614 	size_t size = 0;
615 
616 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
617 	while (node != NULL) {
618 		if (node->offset != size) {
619 			panic("net_buffer %p: bad node %p offset (%lu vs. %lu)",
620 				buffer, node, node->offset, size);
621 			return;
622 		}
623 		size += node->used;
624 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
625 	}
626 
627 	if (size != buffer->size) {
628 		panic("net_buffer %p size != sum of its data node sizes (%lu vs. %lu)",
629 			buffer, buffer->size, size);
630 		return;
631 	}
632 }
633 
634 
635 #if 0
636 static void
637 check_buffer_contents(net_buffer *buffer, size_t offset, const void* data,
638 	size_t size)
639 {
640 	void* bufferData = malloc(size);
641 	if (bufferData == NULL)
642 		return;
643 
644 	if (read_data(buffer, offset, bufferData, size) == B_OK) {
645 		if (memcmp(bufferData, data, size) != 0) {
646 			int32 index = 0;
647 			while (((uint8*)data)[index] == ((uint8*)bufferData)[index])
648 				index++;
649 			panic("check_buffer_contents(): contents check failed at index "
650 				"%ld, buffer: %p, offset: %lu, size: %lu", index, buffer,
651 				offset, size);
652 		}
653 	} else {
654 		panic("failed to read from buffer %p, offset: %lu, size: %lu",
655 			buffer, offset, size);
656 	}
657 
658 	free(bufferData);
659 }
660 
661 
662 static void
663 check_buffer_contents(net_buffer *buffer, size_t offset, net_buffer *source,
664 	size_t sourceOffset, size_t size)
665 {
666 	void* bufferData = malloc(size);
667 	if (bufferData == NULL)
668 		return;
669 
670 	if (read_data(source, sourceOffset, bufferData, size) == B_OK) {
671 		check_buffer_contents(buffer, offset, bufferData, size);
672 	} else {
673 		panic("failed to read from source buffer %p, offset: %lu, size: %lu",
674 			source, sourceOffset, size);
675 	}
676 
677 	free(bufferData);
678 }
679 #endif
680 
681 
682 # 	define CHECK_BUFFER(buffer)	check_buffer(buffer)
683 #else
684 # 	define CHECK_BUFFER(buffer)	do {} while (false)
685 #endif	// !PARANOID_BUFFER_CHECK
686 
687 
688 static inline data_header *
689 allocate_data_header()
690 {
691 #if ENABLE_DEBUGGER_COMMANDS
692 	atomic_add(&sAllocatedDataHeaderCount, 1);
693 	atomic_add(&sEverAllocatedDataHeaderCount, 1);
694 #endif
695 	return (data_header *)object_cache_alloc(sDataNodeCache, CACHE_DONT_SLEEP);
696 }
697 
698 
699 static inline net_buffer_private *
700 allocate_net_buffer()
701 {
702 #if ENABLE_DEBUGGER_COMMANDS
703 	atomic_add(&sAllocatedNetBufferCount, 1);
704 	atomic_add(&sEverAllocatedNetBufferCount, 1);
705 #endif
706 	return (net_buffer_private *)object_cache_alloc(sNetBufferCache,
707 		CACHE_DONT_SLEEP);
708 }
709 
710 
711 static inline void
712 free_data_header(data_header *header)
713 {
714 #if ENABLE_DEBUGGER_COMMANDS
715 	if (header != NULL)
716 		atomic_add(&sAllocatedDataHeaderCount, -1);
717 #endif
718 	object_cache_free(sDataNodeCache, header);
719 }
720 
721 
722 static inline void
723 free_net_buffer(net_buffer_private *buffer)
724 {
725 #if ENABLE_DEBUGGER_COMMANDS
726 	if (buffer != NULL)
727 		atomic_add(&sAllocatedNetBufferCount, -1);
728 #endif
729 	object_cache_free(sNetBufferCache, buffer);
730 }
731 
732 
733 static data_header *
734 create_data_header(size_t headerSpace)
735 {
736 	data_header *header = allocate_data_header();
737 	if (header == NULL)
738 		return NULL;
739 
740 	header->ref_count = 1;
741 	header->physical_address = 0;
742 		// TODO: initialize this correctly
743 	header->space.size = headerSpace;
744 	header->space.free = headerSpace;
745 	header->data_end = (uint8 *)header + DATA_HEADER_SIZE;
746 	header->tail_space = (uint8 *)header + BUFFER_SIZE - header->data_end
747 		- headerSpace;
748 	header->first_free = NULL;
749 
750 	TRACE(("%ld:   create new data header %p\n", find_thread(NULL), header));
751 	T2(CreateDataHeader(header));
752 	return header;
753 }
754 
755 
756 static void
757 release_data_header(data_header *header)
758 {
759 	int32 refCount = atomic_add(&header->ref_count, -1);
760 	T2(ReleaseDataHeader(header, refCount - 1));
761 	if (refCount != 1)
762 		return;
763 
764 	TRACE(("%ld:   free header %p\n", find_thread(NULL), header));
765 	free_data_header(header);
766 }
767 
768 
769 inline void
770 acquire_data_header(data_header *header)
771 {
772 	int32 refCount = atomic_add(&header->ref_count, 1);
773 	(void)refCount;
774 	T2(AcquireDataHeader(header, refCount + 1));
775 }
776 
777 
778 static void
779 free_data_header_space(data_header *header, uint8 *data, size_t size)
780 {
781 	if (size < sizeof(free_data))
782 		size = sizeof(free_data);
783 
784 	free_data *freeData = (free_data *)data;
785 	freeData->next = header->first_free;
786 	freeData->size = size;
787 
788 	header->first_free = freeData;
789 }
790 
791 
792 /*!
793 	Tries to allocate \a size bytes from the free space in the header.
794 */
795 static uint8 *
796 alloc_data_header_space(data_header *header, size_t size)
797 {
798 	if (size < sizeof(free_data))
799 		size = sizeof(free_data);
800 	size = _ALIGN(size);
801 
802 	if (header->first_free != NULL && header->first_free->size >= size) {
803 		// the first entry of the header space matches the allocation's needs
804 // TODO: If the free space is greater than what shall be allocated, we leak
805 // the remainder of the space. We should only allocate multiples of
806 // _ALIGN(sizeof(free_data)) and split free space in this case. It's not that
807 // pressing, since the only thing allocated ATM are data_nodes, and thus the
808 // free space entries will always have the right size.
809 		uint8 *data = (uint8 *)header->first_free;
810 		header->first_free = header->first_free->next;
811 		return data;
812 	}
813 
814 	if (header->space.free < size) {
815 		// there is no free space left, search free list
816 		free_data *freeData = header->first_free;
817 		free_data *last = NULL;
818 		while (freeData != NULL) {
819 			if (last != NULL && freeData->size >= size) {
820 				// take this one
821 				last->next = freeData->next;
822 				return (uint8 *)freeData;
823 			}
824 
825 			last = freeData;
826 			freeData = freeData->next;
827 		}
828 
829 		return NULL;
830 	}
831 
832 	// allocate new space
833 
834 	uint8 *data = header->data_end;
835 	header->data_end += size;
836 	header->space.free -= size;
837 
838 	return data;
839 }
840 
841 
842 static uint8 *
843 alloc_data_header_space(net_buffer_private *buffer, size_t size,
844 	data_header **_header = NULL)
845 {
846 	// try to allocate in our current allocation header
847 	uint8 *allocated = alloc_data_header_space(buffer->allocation_header, size);
848 	if (allocated == NULL) {
849 		// not enough header space left -- create a fresh buffer for headers
850 		data_header *header = create_data_header(MAX_FREE_BUFFER_SIZE);
851 		if (header == NULL)
852 			return NULL;
853 
854 		// release our reference to the old header -- it will will stay around
855 		// until the last reference to it is released
856 		release_data_header(buffer->allocation_header);
857 		buffer->allocation_header = header;
858 			// We keep the initial reference.
859 
860 		// now the allocation can only fail, if size is too big
861 		allocated = alloc_data_header_space(buffer->allocation_header, size);
862 	}
863 
864 	if (_header != NULL)
865 		*_header = buffer->allocation_header;
866 
867 	return allocated;
868 }
869 
870 
871 static data_node *
872 add_first_data_node(data_header *header)
873 {
874 	data_node *node = (data_node *)alloc_data_header_space(header,
875 		sizeof(data_node));
876 	if (node == NULL)
877 		return NULL;
878 
879 	TRACE(("%ld:   add first data node %p to header %p\n", find_thread(NULL),
880 		node, header));
881 
882 	acquire_data_header(header);
883 
884 	memset(node, 0, sizeof(struct data_node));
885 	node->located = header;
886 	node->header = header;
887 	node->offset = 0;
888 	node->start = header->data_end + header->space.free;
889 	node->used = 0;
890 	node->flags = 0;
891 
892 	return node;
893 }
894 
895 
896 static data_node *
897 add_data_node(net_buffer_private *buffer, data_header *header)
898 {
899 	data_header *located;
900 	data_node *node = (data_node *)alloc_data_header_space(buffer,
901 		sizeof(data_node), &located);
902 	if (node == NULL)
903 		return NULL;
904 
905 	TRACE(("%ld:   add data node %p to header %p\n", find_thread(NULL), node,
906 		header));
907 
908 	acquire_data_header(header);
909 	if (located != header)
910 		acquire_data_header(located);
911 
912 	memset(node, 0, sizeof(struct data_node));
913 	node->located = located;
914 	node->header = header;
915 	node->flags = 0;
916 	return node;
917 }
918 
919 
920 void
921 remove_data_node(data_node *node)
922 {
923 	data_header *located = node->located;
924 
925 	TRACE(("%ld:   remove data node %p from header %p (located %p)\n",
926 		find_thread(NULL), node, node->header, located));
927 
928 	// Move all used and tail space to the header space, which is useful in case
929 	// this is the first node of a buffer (i.e. the header is an allocation
930 	// header).
931 	node->FreeSpace();
932 
933 	if (located != node->header)
934 		release_data_header(node->header);
935 
936 	if (located == NULL)
937 		return;
938 
939 	free_data_header_space(located, (uint8 *)node, sizeof(data_node));
940 
941 	release_data_header(located);
942 }
943 
944 
945 static inline data_node *
946 get_node_at_offset(net_buffer_private *buffer, size_t offset)
947 {
948 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
949 	while (node->offset + node->used <= offset) {
950 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
951 		if (node == NULL)
952 			return NULL;
953 	}
954 
955 	return node;
956 }
957 
958 
959 static void
960 copy_metadata(net_buffer *destination, const net_buffer *source)
961 {
962 	memcpy(destination->source, source->source,
963 		min_c(source->source->sa_len, sizeof(sockaddr_storage)));
964 	memcpy(destination->destination, source->destination,
965 		min_c(source->destination->sa_len, sizeof(sockaddr_storage)));
966 
967 	destination->flags = source->flags;
968 	destination->interface = source->interface;
969 	destination->offset = source->offset;
970 	destination->size = source->size;
971 	destination->protocol = source->protocol;
972 	destination->type = source->type;
973 }
974 
975 
976 //	#pragma mark - module API
977 
978 
979 static net_buffer *
980 create_buffer(size_t headerSpace)
981 {
982 	net_buffer_private *buffer = allocate_net_buffer();
983 	if (buffer == NULL)
984 		return NULL;
985 
986 	TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
987 
988 	// Make sure headerSpace is valid and at least the initial node fits.
989 	headerSpace = _ALIGN(headerSpace);
990 	if (headerSpace < DATA_NODE_SIZE)
991 		headerSpace = DATA_NODE_SIZE;
992 	else if (headerSpace > MAX_FREE_BUFFER_SIZE)
993 		headerSpace = MAX_FREE_BUFFER_SIZE;
994 
995 	data_header *header = create_data_header(headerSpace);
996 	if (header == NULL) {
997 		free_net_buffer(buffer);
998 		return NULL;
999 	}
1000 	buffer->allocation_header = header;
1001 
1002 	data_node *node = add_first_data_node(header);
1003 
1004 	list_init(&buffer->buffers);
1005 	list_add_item(&buffer->buffers, node);
1006 
1007 	buffer->ancillary_data = NULL;
1008 
1009 	buffer->source = (sockaddr *)&buffer->storage.source;
1010 	buffer->destination = (sockaddr *)&buffer->storage.destination;
1011 
1012 	buffer->storage.source.ss_len = 0;
1013 	buffer->storage.destination.ss_len = 0;
1014 
1015 	buffer->interface = NULL;
1016 	buffer->offset = 0;
1017 	buffer->flags = 0;
1018 	buffer->size = 0;
1019 
1020 	buffer->type = -1;
1021 
1022 	CHECK_BUFFER(buffer);
1023 	CREATE_PARANOIA_CHECK_SET(buffer, "net_buffer");
1024 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1025 		sizeof(buffer->size));
1026 
1027 	T(Create(headerSpace, buffer));
1028 
1029 	return buffer;
1030 }
1031 
1032 
1033 static void
1034 free_buffer(net_buffer *_buffer)
1035 {
1036 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1037 
1038 	TRACE(("%ld: free buffer %p\n", find_thread(NULL), buffer));
1039 	T(Free(buffer));
1040 
1041 	CHECK_BUFFER(buffer);
1042 	DELETE_PARANOIA_CHECK_SET(buffer);
1043 
1044 	data_node *node;
1045 	while ((node = (data_node *)list_remove_head_item(&buffer->buffers)) != NULL) {
1046 		remove_data_node(node);
1047 	}
1048 
1049 	delete_ancillary_data_container(buffer->ancillary_data);
1050 
1051 	release_data_header(buffer->allocation_header);
1052 
1053 	free_net_buffer(buffer);
1054 }
1055 
1056 
1057 /*!	Creates a duplicate of the \a buffer. The new buffer does not share internal
1058 	storage; they are completely independent from each other.
1059 */
1060 static net_buffer *
1061 duplicate_buffer(net_buffer *_buffer)
1062 {
1063 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1064 
1065 	ParanoiaChecker _(buffer);
1066 
1067 	TRACE(("%ld: duplicate_buffer(buffer %p)\n", find_thread(NULL), buffer));
1068 
1069 	// TODO: We might want to choose a better header space. The minimal
1070 	// one doesn't allow to prepend any data without allocating a new header.
1071 	// The same holds for appending cloned data.
1072 	net_buffer *duplicate = create_buffer(DATA_NODE_SIZE);
1073 	if (duplicate == NULL)
1074 		return NULL;
1075 
1076 	TRACE(("%ld:   duplicate: %p)\n", find_thread(NULL), duplicate));
1077 
1078 	// copy the data from the source buffer
1079 
1080 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
1081 	while (node != NULL) {
1082 		if (append_data(duplicate, node->start, node->used) < B_OK) {
1083 			free_buffer(duplicate);
1084 			CHECK_BUFFER(buffer);
1085 			return NULL;
1086 		}
1087 
1088 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1089 	}
1090 
1091 	copy_metadata(duplicate, buffer);
1092 
1093 	CHECK_BUFFER(buffer);
1094 	CHECK_BUFFER(duplicate);
1095 	RUN_PARANOIA_CHECKS(duplicate);
1096 
1097 	T(Duplicate(buffer, duplicate));
1098 
1099 	return duplicate;
1100 }
1101 
1102 
1103 /*!	Clones the buffer by grabbing another reference to the underlying data.
1104 	If that data changes, it will be changed in the clone as well.
1105 
1106 	If \a shareFreeSpace is \c true, the cloned buffer may claim the free
1107 	space in the original buffer as the original buffer can still do. If you
1108 	are using this, it's your responsibility that only one of the buffers
1109 	will do this.
1110 */
1111 static net_buffer *
1112 clone_buffer(net_buffer *_buffer, bool shareFreeSpace)
1113 {
1114 // TODO: See, if the commented out code can be fixed in a safe way. We could
1115 // probably place cloned nodes on a header not belonging to our buffer, if
1116 // we don't free the header space for the node when removing it. Otherwise we
1117 // mess with the header's free list which might at the same time be accessed
1118 // by another thread.
1119 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1120 
1121 	net_buffer *clone = create_buffer(MAX_FREE_BUFFER_SIZE);
1122 	if (clone == NULL)
1123 		return NULL;
1124 
1125 	if (append_cloned_data(clone, buffer, 0, buffer->size) != B_OK) {
1126 		free_buffer(clone);
1127 		return NULL;
1128 	}
1129 
1130 	copy_metadata(clone, buffer);
1131 
1132 	return clone;
1133 
1134 #if 0
1135 	ParanoiaChecker _(buffer);
1136 
1137 	TRACE(("%ld: clone_buffer(buffer %p)\n", find_thread(NULL), buffer));
1138 
1139 	net_buffer_private *clone = allocate_net_buffer();
1140 	if (clone == NULL)
1141 		return NULL;
1142 
1143 	TRACE(("%ld:   clone: %p\n", find_thread(NULL), buffer));
1144 
1145 	data_node *sourceNode = (data_node *)list_get_first_item(&buffer->buffers);
1146 	if (sourceNode == NULL) {
1147 		free_net_buffer(clone);
1148 		return NULL;
1149 	}
1150 
1151 	clone->source = (sockaddr *)&clone->storage.source;
1152 	clone->destination = (sockaddr *)&clone->storage.destination;
1153 
1154 	list_init(&clone->buffers);
1155 
1156 	// grab reference to this buffer - all additional nodes will get
1157 	// theirs in add_data_node()
1158 	acquire_data_header(sourceNode->header);
1159 	data_node *node = &clone->first_node;
1160 	node->header = sourceNode->header;
1161 	node->located = NULL;
1162 	node->used_header_space = &node->own_header_space;
1163 
1164 	while (sourceNode != NULL) {
1165 		node->start = sourceNode->start;
1166 		node->used = sourceNode->used;
1167 		node->offset = sourceNode->offset;
1168 
1169 		if (shareFreeSpace) {
1170 			// both buffers could claim the free space - note that this option
1171 			// has to be used carefully
1172 			node->used_header_space = &sourceNode->header->space;
1173 			node->tail_space = sourceNode->tail_space;
1174 		} else {
1175 			// the free space stays with the original buffer
1176 			node->used_header_space->size = 0;
1177 			node->used_header_space->free = 0;
1178 			node->tail_space = 0;
1179 		}
1180 
1181 		// add node to clone's list of buffers
1182 		list_add_item(&clone->buffers, node);
1183 
1184 		sourceNode = (data_node *)list_get_next_item(&buffer->buffers, sourceNode);
1185 		if (sourceNode == NULL)
1186 			break;
1187 
1188 		node = add_data_node(sourceNode->header);
1189 		if (node == NULL) {
1190 			// There was not enough space left for another node in this buffer
1191 			// TODO: handle this case!
1192 			panic("clone buffer hits size limit... (fix me)");
1193 			free_net_buffer(clone);
1194 			return NULL;
1195 		}
1196 	}
1197 
1198 	copy_metadata(clone, buffer);
1199 
1200 	CREATE_PARANOIA_CHECK_SET(clone, "net_buffer");
1201 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, clone, &clone->size,
1202 		sizeof(clone->size));
1203 	CHECK_BUFFER(buffer);
1204 	CHECK_BUFFER(clone);
1205 
1206 	T(Clone(buffer, shareFreeSpace, clone));
1207 
1208 	return clone;
1209 #endif
1210 }
1211 
1212 
1213 /*!
1214 	Split the buffer at offset, the header data
1215 	is returned as new buffer.
1216 	TODO: optimize and avoid making a copy.
1217 */
1218 static net_buffer *
1219 split_buffer(net_buffer *from, uint32 offset)
1220 {
1221 	// TODO: Copying the whole buffer becomes less and less efficient with
1222 	// greater size - offset differences. What we actually want is a method
1223 	// to copy data from one buffer to another. Then the following should be:
1224 	// create buffer, resize, copy data. An additional append_data_from_buffer()
1225 	// method would be even better.
1226 	net_buffer *buffer = duplicate_buffer(from);
1227 	if (buffer == NULL)
1228 		return NULL;
1229 
1230 	ParanoiaChecker _(from);
1231 	ParanoiaChecker _2(buffer);
1232 
1233 	TRACE(("%ld: split_buffer(buffer %p -> %p, offset %ld)\n",
1234 		find_thread(NULL), from, buffer, offset));
1235 
1236 	if (trim_data(buffer, offset) == B_OK) {
1237 		if (remove_header(from, offset) == B_OK) {
1238 			CHECK_BUFFER(from);
1239 			CHECK_BUFFER(buffer);
1240 			T(Split(from, offset, buffer));
1241 			return buffer;
1242 		}
1243 	}
1244 
1245 	free_buffer(buffer);
1246 	CHECK_BUFFER(from);
1247 	return NULL;
1248 }
1249 
1250 
1251 /*!
1252 	Merges the second buffer with the first. If \a after is \c true, the
1253 	second buffer's contents will be appended to the first ones, else they
1254 	will be prepended.
1255 	The second buffer will be freed if this function succeeds.
1256 */
1257 static status_t
1258 merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
1259 {
1260 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1261 	net_buffer_private *with = (net_buffer_private *)_with;
1262 	if (with == NULL)
1263 		return B_BAD_VALUE;
1264 
1265 	TRACE(("%ld: merge buffer %p with %p (%s)\n", find_thread(NULL), buffer,
1266 		with, after ? "after" : "before"));
1267 	T(Merge(buffer, with, after));
1268 	//dump_buffer(buffer);
1269 	//dprintf("with:\n");
1270 	//dump_buffer(with);
1271 
1272 	ParanoiaChecker _(buffer);
1273 	CHECK_BUFFER(buffer);
1274 	CHECK_BUFFER(with);
1275 
1276 	// TODO: this is currently very simplistic, I really need to finish the
1277 	//	harder part of this implementation (data_node management per header)
1278 
1279 	data_node *before = NULL;
1280 
1281 // TODO: Do allocating nodes (the only part that can fail) upfront. Put them
1282 // in a list, so we can easily clean up, if necessary.
1283 
1284 	if (!after) {
1285 		// change offset of all nodes already in the buffer
1286 		data_node *node = NULL;
1287 		while (true) {
1288 			node = (data_node *)list_get_next_item(&buffer->buffers, node);
1289 			if (node == NULL)
1290 				break;
1291 
1292 			node->offset += with->size;
1293 			if (before == NULL)
1294 				before = node;
1295 		}
1296 	}
1297 
1298 	data_node *last = NULL;
1299 
1300 	while (true) {
1301 		data_node *node = (data_node *)list_get_next_item(&with->buffers, last);
1302 		if (node == NULL)
1303 			break;
1304 
1305 		if ((uint8 *)node > (uint8 *)node->header
1306 			&& (uint8 *)node < (uint8 *)node->header + BUFFER_SIZE) {
1307 			// The node is already in the buffer, we can just move it
1308 			// over to the new owner
1309 			list_remove_item(&with->buffers, node);
1310 		} else {
1311 			// we need a new place for this node
1312 			data_node *newNode = add_data_node(buffer, node->header);
1313 			if (newNode == NULL)
1314 // TODO: try to revert buffers to their initial state!!
1315 				return ENOBUFS;
1316 
1317 			last = node;
1318 			*newNode = *node;
1319 			node = newNode;
1320 				// the old node will get freed with its buffer
1321 		}
1322 
1323 		if (after) {
1324 			list_add_item(&buffer->buffers, node);
1325 			node->offset = buffer->size;
1326 		} else
1327 			list_insert_item_before(&buffer->buffers, before, node);
1328 
1329 		buffer->size += node->used;
1330 	}
1331 
1332 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1333 		sizeof(buffer->size));
1334 
1335 	// the data has been merged completely at this point
1336 	free_buffer(with);
1337 
1338 	//dprintf(" merge result:\n");
1339 	//dump_buffer(buffer);
1340 	CHECK_BUFFER(buffer);
1341 
1342 	return B_OK;
1343 }
1344 
1345 
1346 /*!	Writes into existing allocated memory.
1347 	\return B_BAD_VALUE if you write outside of the buffers current
1348 		bounds.
1349 */
1350 static status_t
1351 write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size)
1352 {
1353 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1354 
1355 	T(Write(buffer, offset, data, size));
1356 
1357 	ParanoiaChecker _(buffer);
1358 
1359 	if (offset + size > buffer->size)
1360 		return B_BAD_VALUE;
1361 	if (size == 0)
1362 		return B_OK;
1363 
1364 	// find first node to write into
1365 	data_node *node = get_node_at_offset(buffer, offset);
1366 	if (node == NULL)
1367 		return B_BAD_VALUE;
1368 
1369 	offset -= node->offset;
1370 
1371 	while (true) {
1372 		size_t written = min_c(size, node->used - offset);
1373 		memcpy(node->start + offset, data, written);
1374 
1375 		size -= written;
1376 		if (size == 0)
1377 			break;
1378 
1379 		offset = 0;
1380 		data = (void *)((uint8 *)data + written);
1381 
1382 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1383 		if (node == NULL)
1384 			return B_BAD_VALUE;
1385 	}
1386 
1387 	CHECK_BUFFER(buffer);
1388 
1389 	return B_OK;
1390 }
1391 
1392 
1393 static status_t
1394 read_data(net_buffer *_buffer, size_t offset, void *data, size_t size)
1395 {
1396 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1397 
1398 	T(Read(buffer, offset, data, size));
1399 
1400 	ParanoiaChecker _(buffer);
1401 
1402 	if (offset + size > buffer->size)
1403 		return B_BAD_VALUE;
1404 	if (size == 0)
1405 		return B_OK;
1406 
1407 	// find first node to read from
1408 	data_node *node = get_node_at_offset(buffer, offset);
1409 	if (node == NULL)
1410 		return B_BAD_VALUE;
1411 
1412 	offset -= node->offset;
1413 
1414 	while (true) {
1415 		size_t bytesRead = min_c(size, node->used - offset);
1416 		memcpy(data, node->start + offset, bytesRead);
1417 
1418 		size -= bytesRead;
1419 		if (size == 0)
1420 			break;
1421 
1422 		offset = 0;
1423 		data = (void *)((uint8 *)data + bytesRead);
1424 
1425 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1426 		if (node == NULL)
1427 			return B_BAD_VALUE;
1428 	}
1429 
1430 	CHECK_BUFFER(buffer);
1431 
1432 	return B_OK;
1433 }
1434 
1435 
1436 static status_t
1437 prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
1438 {
1439 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1440 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
1441 
1442 	T(PrependSize(buffer, size));
1443 
1444 	ParanoiaChecker _(buffer);
1445 
1446 	TRACE(("%ld: prepend_size(buffer %p, size %ld) [has %u]\n",
1447 		find_thread(NULL), buffer, size, node->HeaderSpace()));
1448 	//dump_buffer(buffer);
1449 
1450 	if (node->HeaderSpace() < size) {
1451 		// we need to prepend new buffers
1452 
1453 		size_t bytesLeft = size;
1454 		size_t sizePrepended = 0;
1455 		do {
1456 			if (node->HeaderSpace() == 0) {
1457 				size_t headerSpace = MAX_FREE_BUFFER_SIZE;
1458 				data_header *header = create_data_header(headerSpace);
1459 				if (header == NULL) {
1460 					remove_header(buffer, sizePrepended);
1461 					return B_NO_MEMORY;
1462 				}
1463 
1464 				data_node *previous = node;
1465 
1466 				node = (data_node *)add_first_data_node(header);
1467 
1468 				list_insert_item_before(&buffer->buffers, previous, node);
1469 
1470 				// Release the initial reference to the header, so that it will
1471 				// be deleted when the node is removed.
1472 				release_data_header(header);
1473 			}
1474 
1475 			size_t willConsume = min_c(bytesLeft, node->HeaderSpace());
1476 
1477 			node->SubtractHeaderSpace(willConsume);
1478 			node->start -= willConsume;
1479 			node->used += willConsume;
1480 			bytesLeft -= willConsume;
1481 			sizePrepended += willConsume;
1482 		} while (bytesLeft > 0);
1483 
1484 		// correct data offset in all nodes
1485 
1486 		size_t offset = 0;
1487 		node = NULL;
1488 		while ((node = (data_node *)list_get_next_item(&buffer->buffers,
1489 				node)) != NULL) {
1490 			node->offset = offset;
1491 			offset += node->used;
1492 		}
1493 
1494 		if (_contiguousBuffer)
1495 			*_contiguousBuffer = NULL;
1496 	} else {
1497 		// the data fits into this buffer
1498 		node->SubtractHeaderSpace(size);
1499 		node->start -= size;
1500 		node->used += size;
1501 
1502 		if (_contiguousBuffer)
1503 			*_contiguousBuffer = node->start;
1504 
1505 		// adjust offset of following nodes
1506 		while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) {
1507 			node->offset += size;
1508 		}
1509 	}
1510 
1511 	buffer->size += size;
1512 
1513 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1514 		sizeof(buffer->size));
1515 
1516 	//dprintf(" prepend_size result:\n");
1517 	//dump_buffer(buffer);
1518 	CHECK_BUFFER(buffer);
1519 	return B_OK;
1520 }
1521 
1522 
1523 static status_t
1524 prepend_data(net_buffer *buffer, const void *data, size_t size)
1525 {
1526 	void *contiguousBuffer;
1527 	status_t status = prepend_size(buffer, size, &contiguousBuffer);
1528 	if (status < B_OK)
1529 		return status;
1530 
1531 	if (contiguousBuffer)
1532 		memcpy(contiguousBuffer, data, size);
1533 	else
1534 		write_data(buffer, 0, data, size);
1535 
1536 	//dprintf(" prepend result:\n");
1537 	//dump_buffer(buffer);
1538 
1539 	return B_OK;
1540 }
1541 
1542 
1543 static status_t
1544 append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
1545 {
1546 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1547 	data_node *node = (data_node *)list_get_last_item(&buffer->buffers);
1548 
1549 	T(AppendSize(buffer, size));
1550 
1551 	ParanoiaChecker _(buffer);
1552 
1553 	TRACE(("%ld: append_size(buffer %p, size %ld)\n", find_thread(NULL),
1554 		buffer, size));
1555 	//dump_buffer(buffer);
1556 
1557 	if (node->TailSpace() < size) {
1558 		// we need to append at least one new buffer
1559 		uint32 previousTailSpace = node->TailSpace();
1560 		uint32 headerSpace = DATA_NODE_SIZE;
1561 		uint32 sizeUsed = MAX_FREE_BUFFER_SIZE - headerSpace;
1562 
1563 		// allocate space left in the node
1564 		node->SetTailSpace(0);
1565 		node->used += previousTailSpace;
1566 		buffer->size += previousTailSpace;
1567 		uint32 sizeAdded = previousTailSpace;
1568 		SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1569 			sizeof(buffer->size));
1570 
1571 		// allocate all buffers
1572 
1573 		while (sizeAdded < size) {
1574 			if (sizeAdded + sizeUsed > size) {
1575 				// last data_header and not all available space is used
1576 				sizeUsed = size - sizeAdded;
1577 			}
1578 
1579 			data_header *header = create_data_header(headerSpace);
1580 			if (header == NULL) {
1581 				remove_trailer(buffer, sizeAdded);
1582 				return B_NO_MEMORY;
1583 			}
1584 
1585 			node = add_first_data_node(header);
1586 
1587 			node->SetTailSpace(node->TailSpace() - sizeUsed);
1588 			node->used = sizeUsed;
1589 			node->offset = buffer->size;
1590 
1591 			buffer->size += sizeUsed;
1592 			sizeAdded += sizeUsed;
1593 			SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1594 				sizeof(buffer->size));
1595 
1596 			list_add_item(&buffer->buffers, node);
1597 
1598 			// Release the initial reference to the header, so that it will
1599 			// be deleted when the node is removed.
1600 			release_data_header(header);
1601 		}
1602 
1603 		if (_contiguousBuffer)
1604 			*_contiguousBuffer = NULL;
1605 
1606 		//dprintf(" append result 1:\n");
1607 		//dump_buffer(buffer);
1608 		CHECK_BUFFER(buffer);
1609 
1610 		return B_OK;
1611 	}
1612 
1613 	// the data fits into this buffer
1614 	node->SetTailSpace(node->TailSpace() - size);
1615 
1616 	if (_contiguousBuffer)
1617 		*_contiguousBuffer = node->start + node->used;
1618 
1619 	node->used += size;
1620 	buffer->size += size;
1621 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1622 		sizeof(buffer->size));
1623 
1624 	//dprintf(" append result 2:\n");
1625 	//dump_buffer(buffer);
1626 	CHECK_BUFFER(buffer);
1627 
1628 	return B_OK;
1629 }
1630 
1631 
1632 static status_t
1633 append_data(net_buffer *buffer, const void *data, size_t size)
1634 {
1635 	size_t used = buffer->size;
1636 
1637 	void *contiguousBuffer;
1638 	status_t status = append_size(buffer, size, &contiguousBuffer);
1639 	if (status < B_OK)
1640 		return status;
1641 
1642 	if (contiguousBuffer)
1643 		memcpy(contiguousBuffer, data, size);
1644 	else
1645 		write_data(buffer, used, data, size);
1646 
1647 	return B_OK;
1648 }
1649 
1650 
1651 /*!
1652 	Removes bytes from the beginning of the buffer.
1653 */
1654 static status_t
1655 remove_header(net_buffer *_buffer, size_t bytes)
1656 {
1657 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1658 
1659 	T(RemoveHeader(buffer, bytes));
1660 
1661 	ParanoiaChecker _(buffer);
1662 
1663 	if (bytes > buffer->size)
1664 		return B_BAD_VALUE;
1665 
1666 	TRACE(("%ld: remove_header(buffer %p, %ld bytes)\n", find_thread(NULL),
1667 		buffer, bytes));
1668 	//dump_buffer(buffer);
1669 
1670 	size_t left = bytes;
1671 	data_node *node = NULL;
1672 
1673 	while (left >= 0) {
1674 		node = (data_node *)list_get_first_item(&buffer->buffers);
1675 		if (node == NULL) {
1676 			if (left == 0)
1677 				break;
1678 			CHECK_BUFFER(buffer);
1679 			return B_ERROR;
1680 		}
1681 
1682 		if (node->used > left)
1683 			break;
1684 
1685 		// node will be removed completely
1686 		list_remove_item(&buffer->buffers, node);
1687 		left -= node->used;
1688 		remove_data_node(node);
1689 		node = NULL;
1690 	}
1691 
1692 	// cut remaining node, if any
1693 
1694 	if (node != NULL) {
1695 		size_t cut = min_c(node->used, left);
1696 		node->offset = 0;
1697 		node->start += cut;
1698 		node->AddHeaderSpace(cut);
1699 		node->used -= cut;
1700 
1701 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1702 	}
1703 
1704 	// adjust offset of following nodes
1705 	while (node != NULL) {
1706 		node->offset -= bytes;
1707 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1708 	}
1709 
1710 	buffer->size -= bytes;
1711 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1712 		sizeof(buffer->size));
1713 
1714 	//dprintf(" remove result:\n");
1715 	//dump_buffer(buffer);
1716 	CHECK_BUFFER(buffer);
1717 
1718 	return B_OK;
1719 }
1720 
1721 
1722 /*!
1723 	Removes bytes from the end of the buffer.
1724 */
1725 static status_t
1726 remove_trailer(net_buffer *buffer, size_t bytes)
1727 {
1728 	return trim_data(buffer, buffer->size - bytes);
1729 }
1730 
1731 
1732 /*!
1733 	Trims the buffer to the specified \a newSize by removing space from
1734 	the end of the buffer.
1735 */
1736 static status_t
1737 trim_data(net_buffer *_buffer, size_t newSize)
1738 {
1739 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1740 	TRACE(("%ld: trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n",
1741 		find_thread(NULL), buffer, newSize, buffer->size));
1742 	T(Trim(buffer, newSize));
1743 	//dump_buffer(buffer);
1744 
1745 	ParanoiaChecker _(buffer);
1746 
1747 	if (newSize > buffer->size)
1748 		return B_BAD_VALUE;
1749 	if (newSize == buffer->size)
1750 		return B_OK;
1751 
1752 	data_node *node = get_node_at_offset(buffer, newSize);
1753 	if (node == NULL) {
1754 		// trim size greater than buffer size
1755 		return B_BAD_VALUE;
1756 	}
1757 
1758 	int32 diff = node->used + node->offset - newSize;
1759 	node->SetTailSpace(node->TailSpace() + diff);
1760 	node->used -= diff;
1761 
1762 	if (node->used > 0)
1763 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1764 
1765 	while (node != NULL) {
1766 		data_node *next = (data_node *)list_get_next_item(&buffer->buffers, node);
1767 		list_remove_item(&buffer->buffers, node);
1768 		remove_data_node(node);
1769 
1770 		node = next;
1771 	}
1772 
1773 	buffer->size = newSize;
1774 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1775 		sizeof(buffer->size));
1776 
1777 	//dprintf(" trim result:\n");
1778 	//dump_buffer(buffer);
1779 	CHECK_BUFFER(buffer);
1780 
1781 	return B_OK;
1782 }
1783 
1784 
1785 /*!
1786 	Appends data coming from buffer \a source to the buffer \a buffer. It only
1787 	clones the data, though, that is the data is not copied, just referenced.
1788 */
1789 static status_t
1790 append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
1791 	size_t bytes)
1792 {
1793 	if (bytes == 0)
1794 		return B_OK;
1795 
1796 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1797 	net_buffer_private *source = (net_buffer_private *)_source;
1798 	TRACE(("%ld: append_cloned_data(buffer %p, source %p, offset = %ld, "
1799 		"bytes = %ld)\n", find_thread(NULL), buffer, source, offset, bytes));
1800 	T(AppendCloned(buffer, source, offset, bytes));
1801 
1802 	ParanoiaChecker _(buffer);
1803 	ParanoiaChecker _2(source);
1804 
1805 	if (source->size < offset + bytes || source->size < offset)
1806 		return B_BAD_VALUE;
1807 
1808 	// find data_node to start with from the source buffer
1809 	data_node *node = get_node_at_offset(source, offset);
1810 	if (node == NULL) {
1811 		// trim size greater than buffer size
1812 		return B_BAD_VALUE;
1813 	}
1814 
1815 	size_t sizeAppended = 0;
1816 
1817 	while (node != NULL && bytes > 0) {
1818 		data_node *clone = add_data_node(buffer, node->header);
1819 		if (clone == NULL) {
1820 			remove_trailer(buffer, sizeAppended);
1821 			return ENOBUFS;
1822 		}
1823 
1824 		if (offset)
1825 			offset -= node->offset;
1826 
1827 		clone->offset = buffer->size;
1828 		clone->start = node->start + offset;
1829 		clone->used = min_c(bytes, node->used - offset);
1830 		clone->flags |= DATA_NODE_READ_ONLY;
1831 
1832 		list_add_item(&buffer->buffers, clone);
1833 
1834 		offset = 0;
1835 		bytes -= clone->used;
1836 		buffer->size += clone->used;
1837 		sizeAppended += clone->used;
1838 		node = (data_node *)list_get_next_item(&source->buffers, node);
1839 	}
1840 
1841 	if (bytes != 0)
1842 		panic("add_cloned_data() failed, bytes != 0!\n");
1843 
1844 	//dprintf(" append cloned result:\n");
1845 	//dump_buffer(buffer);
1846 	CHECK_BUFFER(source);
1847 	CHECK_BUFFER(buffer);
1848 	SET_PARANOIA_CHECK(PARANOIA_SUSPICIOUS, buffer, &buffer->size,
1849 		sizeof(buffer->size));
1850 
1851 	return B_OK;
1852 }
1853 
1854 
1855 void
1856 set_ancillary_data(net_buffer *buffer, ancillary_data_container *container)
1857 {
1858 	((net_buffer_private*)buffer)->ancillary_data = container;
1859 }
1860 
1861 
1862 ancillary_data_container*
1863 get_ancillary_data(net_buffer *buffer)
1864 {
1865 	return ((net_buffer_private*)buffer)->ancillary_data;
1866 }
1867 
1868 
1869 /*!
1870 	Moves all ancillary data from buffer \c from to the end of the list of
1871 	ancillary data of buffer \c to. Note, that this is the only function that
1872 	transfers or copies ancillary data from one buffer to another.
1873 
1874 	\param from The buffer from which to remove the ancillary data.
1875 	\param to The buffer to which to add the ancillary data.
1876 	\return A pointer to the first of the moved ancillary data, if any, \c NULL
1877 		otherwise.
1878 */
1879 static void *
1880 transfer_ancillary_data(net_buffer *_from, net_buffer *_to)
1881 {
1882 	net_buffer_private *from = (net_buffer_private *)_from;
1883 	net_buffer_private *to = (net_buffer_private *)_to;
1884 
1885 	if (from == NULL || to == NULL)
1886 		return NULL;
1887 
1888 	if (from->ancillary_data == NULL)
1889 		return NULL;
1890 
1891 	if (to->ancillary_data == NULL) {
1892 		// no ancillary data in the target buffer
1893 		to->ancillary_data = from->ancillary_data;
1894 		from->ancillary_data = NULL;
1895 		return next_ancillary_data(to->ancillary_data, NULL, NULL);
1896 	}
1897 
1898 	// both have ancillary data
1899 	void *data = move_ancillary_data(from->ancillary_data,
1900 		to->ancillary_data);
1901 	delete_ancillary_data_container(from->ancillary_data);
1902 	from->ancillary_data = NULL;
1903 
1904 	return data;
1905 }
1906 
1907 
1908 /*!
1909 	Tries to directly access the requested space in the buffer.
1910 	If the space is contiguous, the function will succeed and place a pointer
1911 	to that space into \a _contiguousBuffer.
1912 
1913 	\return B_BAD_VALUE if the offset is outside of the buffer's bounds.
1914 	\return B_ERROR in case the buffer is not contiguous at that location.
1915 */
1916 static status_t
1917 direct_access(net_buffer *_buffer, uint32 offset, size_t size,
1918 	void **_contiguousBuffer)
1919 {
1920 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1921 
1922 	ParanoiaChecker _(buffer);
1923 
1924 	//TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, size));
1925 
1926 	if (offset + size > buffer->size)
1927 		return B_BAD_VALUE;
1928 
1929 	// find node to access
1930 	data_node *node = get_node_at_offset(buffer, offset);
1931 	if (node == NULL)
1932 		return B_BAD_VALUE;
1933 
1934 	offset -= node->offset;
1935 
1936 	if (size > node->used - offset)
1937 		return B_ERROR;
1938 
1939 	*_contiguousBuffer = node->start + offset;
1940 	return B_OK;
1941 }
1942 
1943 
1944 static int32
1945 checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize)
1946 {
1947 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1948 
1949 	if (offset + size > buffer->size || size == 0)
1950 		return B_BAD_VALUE;
1951 
1952 	// find first node to read from
1953 	data_node *node = get_node_at_offset(buffer, offset);
1954 	if (node == NULL)
1955 		return B_ERROR;
1956 
1957 	offset -= node->offset;
1958 
1959 	// Since the maximum buffer size is 65536 bytes, it's impossible
1960 	// to overlap 32 bit - we don't need to handle this overlap in
1961 	// the loop, we can safely do it afterwards
1962 	uint32 sum = 0;
1963 
1964 	while (true) {
1965 		size_t bytes = min_c(size, node->used - offset);
1966 		if ((offset + node->offset) & 1) {
1967 			// if we're at an uneven offset, we have to swap the checksum
1968 			sum += __swap_int16(compute_checksum(node->start + offset, bytes));
1969 		} else
1970 			sum += compute_checksum(node->start + offset, bytes);
1971 
1972 		size -= bytes;
1973 		if (size == 0)
1974 			break;
1975 
1976 		offset = 0;
1977 
1978 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
1979 		if (node == NULL)
1980 			return B_ERROR;
1981 	}
1982 
1983 	while (sum >> 16) {
1984 		sum = (sum & 0xffff) + (sum >> 16);
1985 	}
1986 
1987 	if (!finalize)
1988 		return (uint16)sum;
1989 
1990 	return (uint16)~sum;
1991 }
1992 
1993 
1994 static uint32
1995 get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount)
1996 {
1997 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
1998 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
1999 	uint32 count = 0;
2000 
2001 	while (node != NULL && count < vecCount) {
2002 		if (node->used > 0) {
2003 			iovecs[count].iov_base = node->start;
2004 			iovecs[count].iov_len = node->used;
2005 			count++;
2006 		}
2007 
2008 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
2009 	}
2010 
2011 	return count;
2012 }
2013 
2014 
2015 static uint32
2016 count_iovecs(net_buffer *_buffer)
2017 {
2018 	net_buffer_private *buffer = (net_buffer_private *)_buffer;
2019 	data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
2020 	uint32 count = 0;
2021 
2022 	while (node != NULL) {
2023 		if (node->used > 0)
2024 			count++;
2025 
2026 		node = (data_node *)list_get_next_item(&buffer->buffers, node);
2027 	}
2028 
2029 	return count;
2030 }
2031 
2032 
2033 static void
2034 swap_addresses(net_buffer *buffer)
2035 {
2036 	std::swap(buffer->source, buffer->destination);
2037 }
2038 
2039 
2040 static status_t
2041 std_ops(int32 op, ...)
2042 {
2043 	switch (op) {
2044 		case B_MODULE_INIT:
2045 			// TODO: improve our code a bit so we can add constructors
2046 			//	and keep around half-constructed buffers in the slab
2047 
2048 			sNetBufferCache = create_object_cache("net buffer cache",
2049 				sizeof(net_buffer_private), 8, NULL, NULL, NULL);
2050 			if (sNetBufferCache == NULL)
2051 				return B_NO_MEMORY;
2052 
2053 			sDataNodeCache = create_object_cache("data node cache", BUFFER_SIZE,
2054 				0, NULL, NULL, NULL);
2055 			if (sDataNodeCache == NULL) {
2056 				delete_object_cache(sNetBufferCache);
2057 				return B_NO_MEMORY;
2058 			}
2059 
2060 #if ENABLE_DEBUGGER_COMMANDS
2061 			add_debugger_command_etc("net_buffer_stats", &dump_net_buffer_stats,
2062 				"Print net buffer statistics",
2063 				"\nPrint net buffer statistics.\n", 0);
2064 #endif
2065 
2066 			return B_OK;
2067 
2068 		case B_MODULE_UNINIT:
2069 #if ENABLE_DEBUGGER_COMMANDS
2070 			remove_debugger_command("net_buffer_stats", &dump_net_buffer_stats);
2071 #endif
2072 			delete_object_cache(sNetBufferCache);
2073 			delete_object_cache(sDataNodeCache);
2074 			return B_OK;
2075 
2076 		default:
2077 			return B_ERROR;
2078 	}
2079 }
2080 
2081 
2082 net_buffer_module_info gNetBufferModule = {
2083 	{
2084 		NET_BUFFER_MODULE_NAME,
2085 		0,
2086 		std_ops
2087 	},
2088 	create_buffer,
2089 	free_buffer,
2090 
2091 	duplicate_buffer,
2092 	clone_buffer,
2093 	split_buffer,
2094 	merge_buffer,
2095 
2096 	prepend_size,
2097 	prepend_data,
2098 	append_size,
2099 	append_data,
2100 	NULL,	// insert
2101 	NULL,	// remove
2102 	remove_header,
2103 	remove_trailer,
2104 	trim_data,
2105 	append_cloned_data,
2106 
2107 	NULL,	// associate_data
2108 
2109 	set_ancillary_data,
2110 	get_ancillary_data,
2111 	transfer_ancillary_data,
2112 
2113 	direct_access,
2114 	read_data,
2115 	write_data,
2116 
2117 	checksum_data,
2118 
2119 	NULL,	// get_memory_map
2120 	get_iovecs,
2121 	count_iovecs,
2122 
2123 	swap_addresses,
2124 
2125 	dump_buffer,	// dump
2126 };
2127 
2128