From 0e5a3fc6c685eef140c485b7f3b2cc72030f1e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 8 Jan 2009 18:31:22 +0000 Subject: [PATCH] * BufferQueue::Get(size_t ...) now always returns successfully if it does not return an empty buffer. This should avoid losing data in case not everything could be appended due to a resource shortage. * Also, it now assures that fNumBytes and fContiguousBytes are always maintained correctly, thanks to Adrian for pointing this out! This should fix bug #2594. * Added extra debug code to BufferQueue::RemoveUntil() so that it checks whether or not fContiguousBytes could be maintained correctly (ie. if this function is called only as thought). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28859 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/protocols/tcp/BufferQueue.cpp | 54 +++++++++++-------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp index e1944c6cbc..4b5b1cf092 100644 --- a/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp +++ b/src/add-ons/kernel/network/protocols/tcp/BufferQueue.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. + * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -183,12 +183,10 @@ BufferQueue::Add(net_buffer *buffer, tcp_sequence sequence) } -/*! - Removes all data in the queue up to the \a sequence number as specified. +/*! Removes all data in the queue up to the \a sequence number as specified. - NOTE: - If there are missing segments in the buffers to be removed, - fContiguousBytes is not maintained correctly! + NOTE: If there are missing segments in the buffers to be removed, + fContiguousBytes is not maintained correctly! */ status_t BufferQueue::RemoveUntil(tcp_sequence sequence) @@ -199,14 +197,20 @@ BufferQueue::RemoveUntil(tcp_sequence sequence) return B_OK; SegmentList::Iterator iterator = fList.GetIterator(); + tcp_sequence lastRemoved = fFirstSequence; net_buffer *buffer = NULL; while ((buffer = iterator.Next()) != NULL && buffer->sequence < sequence) { + ASSERT(lastRemoved == buffer->sequence); + // This assures that the queue has no holes, and fContiguousBytes + // is maintained correctly. + if (sequence >= buffer->sequence + buffer->size) { // remove this buffer completely iterator.Remove(); fNumBytes -= buffer->size; fContiguousBytes -= buffer->size; + lastRemoved = buffer->sequence + buffer->size; gBufferModule->free(buffer); } else { // remove the header as far as needed @@ -229,8 +233,7 @@ BufferQueue::RemoveUntil(tcp_sequence sequence) } -/*! - Clones the requested data in the buffer queue into the provided \a buffer. +/*! Clones the requested data in the buffer queue into the provided \a buffer. */ status_t BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) @@ -260,8 +263,10 @@ BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) if (source == NULL) panic("we should have had that data..."); - if (source->sequence > sequence) - panic("source %p, sequence = %lu (%lu)\n", source, source->sequence, (uint32)sequence); + if (source->sequence > sequence) { + panic("source %p, sequence = %lu (%lu)\n", source, source->sequence, + (uint32)sequence); + } // clone the data @@ -269,7 +274,8 @@ BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) while (source != NULL && bytesLeft > 0) { size_t size = min_c(source->size - offset, bytesLeft); - status_t status = gBufferModule->append_cloned(buffer, source, offset, size); + status_t status = gBufferModule->append_cloned(buffer, source, offset, + size); if (status < B_OK) return status; @@ -282,8 +288,7 @@ BufferQueue::Get(net_buffer *buffer, tcp_sequence sequence, size_t bytes) } -/*! - Creates a new buffer containing \a bytes bytes from the start of the +/*! Creates a new buffer containing \a bytes bytes from the start of the buffer queue. If \a remove is \c true, the data is removed from the queue, if not, the data is cloned from the queue. */ @@ -345,16 +350,21 @@ BufferQueue::Get(size_t bytes, bool remove, net_buffer **_buffer) } } - if (status == B_OK) { - *_buffer = buffer; - if (remove) { - fNumBytes -= bytes; - fContiguousBytes -= bytes; - } - } else - gBufferModule->free(buffer); + if (remove && buffer->size) { + fNumBytes -= buffer->size; + fContiguousBytes -= buffer->size; + } - return status; + // We always return what we got, or else we would lose data + if (status < B_OK && buffer->size == 0) { + // We could not remove any bytes from the buffer, so + // let this call fail. + gBufferModule->free(buffer); + return status; + } + + *_buffer = buffer; + return B_OK; }