1/*
2 * Copyright 2006-2010, 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 */
8
9
10#include "BufferQueue.h"
11
12#include <KernelExport.h>
13#include <arpa/inet.h>
14
15
16//#define TRACE_BUFFER_QUEUE
17#ifdef TRACE_BUFFER_QUEUE
18#	define TRACE(x) dprintf x
19#else
20#	define TRACE(x)
21#endif
22
23#if DEBUG_TCP_BUFFER_QUEUE
24#	define VERIFY() Verify();
25#else
26#	define VERIFY() ;
27#endif
28
29
30BufferQueue::BufferQueue(size_t maxBytes)
31	:
32	fMaxBytes(maxBytes),
33	fNumBytes(0),
34	fContiguousBytes(0),
35	fFirstSequence(0),
36	fLastSequence(0),
37	fPushPointer(0)
38{
39}
40
41
42BufferQueue::~BufferQueue()
43{
44	// free up any buffers left in the queue
45
46	net_buffer *buffer;
47	while ((buffer = fList.RemoveHead()) != NULL) {
48		gBufferModule->free(buffer);
49	}
50}
51
52
53void
54BufferQueue::SetMaxBytes(size_t maxBytes)
55{
56	fMaxBytes = maxBytes;
57}
58
59
60void
61BufferQueue::SetInitialSequence(tcp_sequence sequence)
62{
63	TRACE(("BufferQueue@%p::SetInitialSequence(%" B_PRIu32 ")\n", this,
64		sequence.Number()));
65
66	fFirstSequence = fLastSequence = sequence;
67}
68
69
70
71void
72BufferQueue::Add(net_buffer *buffer)
73{
74	Add(buffer, fLastSequence);
75}
76
77
78void
79BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence)
80{
81	TRACE(("BufferQueue@%p::Add(buffer %p, size %" B_PRIu32 ", sequence %"
82		B_PRIu32 ")\n", this, buffer, buffer->size, sequence.Number()));
83	TRACE(("  in: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %lu, cont: "
84		"%lu\n", fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
85		fContiguousBytes));
86	VERIFY();
87
88	if (tcp_sequence(sequence + buffer->size) <= fFirstSequence
89		|| buffer->size == 0) {
90		// This buffer does not contain any data of interest
91		gBufferModule->free(buffer);
92		return;
93	}
94	if (sequence < fFirstSequence) {
95		// this buffer contains data that is already long gone - trim it
96		gBufferModule->remove_header(buffer,
97			(fFirstSequence - sequence).Number());
98		sequence = fFirstSequence;
99	}
100
101	if (fList.IsEmpty() || sequence >= fLastSequence) {
102		// we usually just add the buffer to the end of the queue
103		fList.Add(buffer);
104		buffer->sequence = sequence.Number();
105
106		if (sequence == fLastSequence
107			&& fLastSequence - fFirstSequence == fNumBytes) {
108			// there is no hole in the buffer, we can make the whole buffer
109			// available
110			fContiguousBytes += buffer->size;
111		}
112
113		fLastSequence = sequence + buffer->size;
114		fNumBytes += buffer->size;
115
116		TRACE(("  out0: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %"
117			B_PRIuSIZE ", cont: %" B_PRIuSIZE "\n",	fFirstSequence.Number(),
118			fLastSequence.Number(), fNumBytes, fContiguousBytes));
119		VERIFY();
120		return;
121	}
122
123	if (fLastSequence < sequence + buffer->size)
124		fLastSequence = sequence + buffer->size;
125
126	// find the place where to insert the buffer into the queue
127
128	SegmentList::ReverseIterator iterator = fList.GetReverseIterator();
129	net_buffer *previous = NULL;
130	net_buffer *next = NULL;
131	while ((previous = iterator.Next()) != NULL) {
132		if (sequence >= previous->sequence) {
133			// The new fragment can be inserted after this one
134			break;
135		}
136
137		next = previous;
138	}
139
140	// check if we have duplicate data, and remove it if that is the case
141	if (previous != NULL) {
142		if (sequence == previous->sequence) {
143			// we already have at least part of this data - ignore new data
144			// whenever it makes sense (because some TCP implementations send
145			// bogus data when probing the window)
146			if (previous->size >= buffer->size) {
147				gBufferModule->free(buffer);
148				buffer = NULL;
149			} else {
150				fList.Remove(previous);
151				fNumBytes -= previous->size;
152				gBufferModule->free(previous);
153			}
154		} else if (tcp_sequence(previous->sequence + previous->size)
155				>= sequence + buffer->size) {
156			// We already know this data
157			gBufferModule->free(buffer);
158			buffer = NULL;
159		} else if (tcp_sequence(previous->sequence + previous->size)
160				> sequence) {
161			// We already have the first part of this buffer
162			gBufferModule->remove_header(buffer,
163				(previous->sequence + previous->size - sequence).Number());
164			sequence = previous->sequence + previous->size;
165		}
166	}
167
168	// "next" always starts at or after the buffer sequence
169	ASSERT(next == NULL || buffer == NULL || next->sequence >= sequence);
170
171	while (buffer != NULL && next != NULL
172		&& tcp_sequence(sequence + buffer->size) > next->sequence) {
173		// we already have at least part of this data
174		if (tcp_sequence(next->sequence + next->size)
175				<= sequence + buffer->size) {
176			net_buffer *remove = next;
177			next = (net_buffer *)next->link.next;
178
179			fList.Remove(remove);
180			fNumBytes -= remove->size;
181			gBufferModule->free(remove);
182		} else if (tcp_sequence(next->sequence) > sequence) {
183			// We have the end of this buffer already
184			gBufferModule->remove_trailer(buffer,
185				(sequence + buffer->size - next->sequence).Number());
186		} else {
187			// We already have this data
188			gBufferModule->free(buffer);
189			buffer = NULL;
190		}
191	}
192
193	if (buffer == NULL) {
194		TRACE(("  out1: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %"
195			B_PRIuSIZE ", cont: %" B_PRIuSIZE "\n", fFirstSequence.Number(),
196			fLastSequence.Number(), fNumBytes, fContiguousBytes));
197		VERIFY();
198		return;
199	}
200
201	fList.InsertBefore(next, buffer);
202	buffer->sequence = sequence.Number();
203	fNumBytes += buffer->size;
204
205	// we might need to update the number of bytes available
206
207	if (fLastSequence - fFirstSequence == fNumBytes)
208		fContiguousBytes = fNumBytes;
209	else if (fFirstSequence + fContiguousBytes == sequence) {
210		// the complicated case: the new segment may have connected almost all
211		// buffers in the queue (but not all, or the above would be true)
212
213		do {
214			fContiguousBytes += buffer->size;
215
216			buffer = (struct net_buffer *)buffer->link.next;
217		} while (buffer != NULL
218			&& fFirstSequence + fContiguousBytes == buffer->sequence);
219	}
220
221	TRACE(("  out2: first: %" B_PRIu32 ", last: %" B_PRIu32 ", num: %lu, cont: "
222		"%lu\n", fFirstSequence.Number(), fLastSequence.Number(), fNumBytes,
223		fContiguousBytes));
224	VERIFY();
225}
226
227
228/*!	Removes all data in the queue up to the \a sequence number as specified.
229
230	NOTE: If there are missing segments in the buffers to be removed,
231	fContiguousBytes is not maintained correctly!
232*/
233status_t
234BufferQueue::RemoveUntil(tcp_sequence sequence)
235{
236	TRACE(("BufferQueue@%p::RemoveUntil(sequence %" B_PRIu32 ")\n", this,
237		sequence.Number()));
238	VERIFY();
239
240	if (sequence < fFirstSequence)
241		return B_OK;
242
243	SegmentList::Iterator iterator = fList.GetIterator();
244	tcp_sequence lastRemoved = fFirstSequence;
245	net_buffer *buffer = NULL;
246	while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) {
247		ASSERT(lastRemoved == buffer->sequence);
248			// This assures that the queue has no holes, and fContiguousBytes
249			// is maintained correctly.
250
251		if (sequence >= buffer->sequence + buffer->size) {
252			// remove this buffer completely
253			iterator.Remove();
254			fNumBytes -= buffer->size;
255
256			fContiguousBytes -= buffer->size;
257			lastRemoved = buffer->sequence + buffer->size;
258			gBufferModule->free(buffer);
259		} else {
260			// remove the header as far as needed
261			size_t size = (sequence - buffer->sequence).Number();
262			gBufferModule->remove_header(buffer, size);
263
264			buffer->sequence += size;
265			fNumBytes -= size;
266			fContiguousBytes -= size;
267			break;
268		}
269	}
270
271	if (fList.IsEmpty())
272		fFirstSequence = fLastSequence;
273	else
274		fFirstSequence = fList.Head()->sequence;
275
276	VERIFY();
277	return B_OK;
278}
279
280
281/*!	Clones the requested data in the buffer queue into the provided \a buffer.
282*/
283status_t
284BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes)
285{
286	TRACE(("BufferQueue@%p::Get(sequence %" B_PRIu32 ", bytes %lu)\n", this,
287		sequence.Number(), bytes));
288	VERIFY();
289
290	if (bytes == 0)
291		return B_OK;
292
293	if (sequence >= fLastSequence || sequence < fFirstSequence) {
294		// we don't have the requested data
295		return B_BAD_VALUE;
296	}
297	if (tcp_sequence(sequence + bytes) > fLastSequence)
298		bytes = (fLastSequence - sequence).Number();
299
300	size_t bytesLeft = bytes;
301
302	// find first buffer matching the sequence
303
304	SegmentList::Iterator iterator = fList.GetIterator();
305	net_buffer *source = NULL;
306	while ((source = iterator.Next()) != NULL) {
307		if (sequence < source->sequence + source->size)
308			break;
309	}
310
311	if (source == NULL)
312		panic("we should have had that data...");
313	if (tcp_sequence(source->sequence) > sequence) {
314		panic("source %p, sequence = %" B_PRIu32 " (%" B_PRIu32 ")\n", source,
315			source->sequence, sequence.Number());
316	}
317
318	// clone the data
319
320	uint32 offset = (sequence - source->sequence).Number();
321
322	while (source != NULL && bytesLeft > 0) {
323		size_t size = min_c(source->size - offset, bytesLeft);
324		status_t status = gBufferModule->append_cloned(buffer, source, offset,
325			size);
326		if (status < B_OK)
327			return status;
328
329		bytesLeft -= size;
330		offset = 0;
331		source = iterator.Next();
332	}
333
334	VERIFY();
335	return B_OK;
336}
337
338
339/*!	Creates a new buffer containing \a bytes bytes from the start of the
340	buffer queue. If \a remove is \c true, the data is removed from the
341	queue, if not, the data is cloned from the queue.
342*/
343status_t
344BufferQueue::Get(size_t bytes, bool remove, net_buffer **_buffer)
345{
346	if (bytes > Available())
347		bytes = Available();
348
349	if (bytes == 0) {
350		// we don't need to create a buffer when there is no data
351		*_buffer = NULL;
352		return B_OK;
353	}
354
355	net_buffer *buffer = fList.First();
356	size_t bytesLeft = bytes;
357	ASSERT(buffer != NULL);
358
359	if (!remove || buffer->size > bytes) {
360		// we need a new buffer
361		buffer = gBufferModule->create(256);
362		if (buffer == NULL)
363			return B_NO_MEMORY;
364	} else {
365		// we can reuse this buffer
366		bytesLeft -= buffer->size;
367		fFirstSequence += buffer->size;
368
369		fList.Remove(buffer);
370	}
371
372	// clone/copy the remaining data
373
374	SegmentList::Iterator iterator = fList.GetIterator();
375	net_buffer *source = NULL;
376	status_t status = B_OK;
377	while (bytesLeft > 0 && (source = iterator.Next()) != NULL) {
378		size_t size = min_c(source->size, bytesLeft);
379		status = gBufferModule->append_cloned(buffer, source, 0, size);
380		if (status < B_OK)
381			break;
382
383		bytesLeft -= size;
384
385		if (!remove)
386			continue;
387
388		// remove either the whole buffer or only the part we cloned
389
390		fFirstSequence += size;
391
392		if (size == source->size) {
393			iterator.Remove();
394			gBufferModule->free(source);
395		} else {
396			gBufferModule->remove_header(source, size);
397			source->sequence += size;
398		}
399	}
400
401	if (remove && buffer->size) {
402		fNumBytes -= buffer->size;
403		fContiguousBytes -= buffer->size;
404	}
405
406	// We always return what we got, or else we would lose data
407	if (status < B_OK && buffer->size == 0) {
408		// We could not remove any bytes from the buffer, so
409		// let this call fail.
410		gBufferModule->free(buffer);
411		VERIFY();
412		return status;
413	}
414
415	*_buffer = buffer;
416	VERIFY();
417	return B_OK;
418}
419
420
421size_t
422BufferQueue::Available(tcp_sequence sequence) const
423{
424	if (sequence > (fFirstSequence + fContiguousBytes).Number())
425		return 0;
426
427	return (fContiguousBytes + fFirstSequence - sequence).Number();
428}
429
430
431void
432BufferQueue::SetPushPointer()
433{
434	if (fList.IsEmpty())
435		fPushPointer = 0;
436	else
437		fPushPointer = fList.Tail()->sequence + fList.Tail()->size;
438}
439
440
441int
442BufferQueue::PopulateSackInfo(tcp_sequence sequence, int maxSackCount,
443	tcp_sack* sacks)
444{
445	SegmentList::ReverseIterator iterator = fList.GetReverseIterator();
446	net_buffer* buffer = iterator.Next();
447
448	int sackCount = 0;
449	TRACE(("BufferQueue::PopulateSackInfo() %" B_PRIu32 "\n",
450		sequence.Number()));
451	while (buffer != NULL && buffer->sequence > sequence) {
452		if (buffer->sequence + buffer->size < sacks[sackCount].left_edge) {
453			if (sackCount + 1 == maxSackCount)
454				break;
455			++sackCount;
456			sacks[sackCount].left_edge = buffer->sequence;
457			sacks[sackCount].right_edge = buffer->sequence + buffer->size;
458		} else {
459			sacks[sackCount].left_edge = buffer->sequence;
460			if (sacks[sackCount].right_edge == 0)
461				sacks[sackCount].right_edge = buffer->sequence + buffer->size;
462		}
463
464		buffer = iterator.Next();
465	}
466
467	if (sacks[0].left_edge != 0) {
468		for (int i = 0; i <= sackCount; ++i) {
469			sacks[i].left_edge = htonl(sacks[i].left_edge);
470			sacks[i].right_edge = htonl(sacks[i].right_edge);
471		}
472		++sackCount;
473	}
474
475	return sackCount;
476}
477
478#if DEBUG_TCP_BUFFER_QUEUE
479
480/*!	Perform a sanity check of the whole queue.
481*/
482void
483BufferQueue::Verify() const
484{
485	ASSERT(Available() == 0 || fList.First() != NULL);
486
487	if (fList.First() == NULL) {
488		ASSERT(fNumBytes == 0);
489		return;
490	}
491
492	SegmentList::ConstIterator iterator = fList.GetIterator();
493	size_t numBytes = 0;
494	size_t contiguousBytes = 0;
495	bool contiguous = true;
496	tcp_sequence last = fFirstSequence;
497
498	while (net_buffer* buffer = iterator.Next()) {
499		if (contiguous && buffer->sequence == last)
500			contiguousBytes += buffer->size;
501		else
502			contiguous = false;
503
504		ASSERT(last <= buffer->sequence);
505		ASSERT(buffer->size > 0);
506
507		numBytes += buffer->size;
508		last = buffer->sequence + buffer->size;
509	}
510
511	ASSERT(last == fLastSequence);
512	ASSERT(contiguousBytes == fContiguousBytes);
513	ASSERT(numBytes == fNumBytes);
514}
515
516
517void
518BufferQueue::Dump() const
519{
520	SegmentList::ConstIterator iterator = fList.GetIterator();
521	int32 number = 0;
522	while (net_buffer* buffer = iterator.Next()) {
523		kprintf("      %" B_PRId32 ". buffer %p, sequence %" B_PRIu32
524			", size %" B_PRIu32 "\n", ++number, buffer, buffer->sequence,
525			buffer->size);
526	}
527}
528
529#endif	// DEBUG_TCP_BUFFER_QUEUE
530