Fixed a bunch of bugs in the net_buffer implementation; it didn't crash before,
but it also didn't create valid buffers in a number of cases: * remove_header() did not work correctly if more than one node had to be removed or came after the first node to be kept. * prepend_size() did not update the offset of the following nodes. * write_data() and read_data() both did not update the data pointer, and thus always copied the same data to every node. * merge_buffer() inserted the nodes in the wrong order when prepending a buffer. * added a dump_buffer() function and lots of additional debug output (currently commented out) * simplified split_buffer() a bit more. * implemented remove_trailer(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19068 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -57,6 +57,26 @@ struct net_buffer_private : net_buffer {
|
|||||||
static status_t append_data(net_buffer *buffer, const void *data, size_t size);
|
static status_t append_data(net_buffer *buffer, const void *data, size_t size);
|
||||||
static status_t trim_data(net_buffer *_buffer, size_t newSize);
|
static status_t trim_data(net_buffer *_buffer, size_t newSize);
|
||||||
static status_t remove_header(net_buffer *_buffer, size_t bytes);
|
static status_t remove_header(net_buffer *_buffer, size_t bytes);
|
||||||
|
static status_t remove_trailer(net_buffer *_buffer, size_t bytes);
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
dump_buffer(net_buffer *_buffer)
|
||||||
|
{
|
||||||
|
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||||
|
|
||||||
|
dprintf("buffer %p, size %ld\n", buffer, buffer->size);
|
||||||
|
data_node *node = NULL;
|
||||||
|
while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) {
|
||||||
|
dprintf(" node %p, offset %ld, used %ld, header %ld, tail %ld, header %p\n",
|
||||||
|
node, node->offset, node->used, node->header_space, node->tail_space, node->header);
|
||||||
|
//dump_block((char *)node->start, node->used, " ");
|
||||||
|
dump_block((char *)node->start, min_c(node->used, 32), " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static data_header *
|
static data_header *
|
||||||
create_data_header(size_t size, size_t headerSpace)
|
create_data_header(size_t size, size_t headerSpace)
|
||||||
@@ -345,24 +365,24 @@ clone_buffer(net_buffer *_buffer, bool shareFreeSpace)
|
|||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Split the buffer at offset, the trailer data
|
Split the buffer at offset, the header data
|
||||||
is returned as new buffer.
|
is returned as new buffer.
|
||||||
TODO: optimize and avoid making a copy.
|
TODO: optimize and avoid making a copy.
|
||||||
*/
|
*/
|
||||||
static net_buffer *
|
static net_buffer *
|
||||||
split_buffer(net_buffer *from, uint32 offset)
|
split_buffer(net_buffer *from, uint32 offset)
|
||||||
{
|
{
|
||||||
status_t err;
|
net_buffer *buffer = duplicate_buffer(from);
|
||||||
net_buffer *buf = duplicate_buffer(from);
|
if (buffer == NULL)
|
||||||
if (buf == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
if ((err = remove_header(buf, offset)) < B_OK)
|
|
||||||
goto fail;
|
TRACE(("split_buffer(buffer %p -> %p, offset %ld)\n", from, buffer, offset));
|
||||||
if ((err = trim_data(from, from->size - offset)) < B_OK)
|
|
||||||
goto fail;
|
if (remove_header(from, offset) == B_OK
|
||||||
return buf;
|
&& trim_data(buffer, offset) == B_OK)
|
||||||
fail:
|
return buffer;
|
||||||
free_buffer(buf);
|
|
||||||
|
free_buffer(buffer);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,9 +402,15 @@ merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
|
|||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
TRACE(("merge buffer %p with %p (%s)\n", buffer, with, after ? "after" : "before"));
|
TRACE(("merge buffer %p with %p (%s)\n", buffer, with, after ? "after" : "before"));
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
//dprintf("with:\n");
|
||||||
|
//dump_buffer(with);
|
||||||
|
|
||||||
// TODO: this is currently very simplistic, I really need to finish the
|
// TODO: this is currently very simplistic, I really need to finish the
|
||||||
// harder part of this implementation (data_node management per header)
|
// harder part of this implementation (data_node management per header)
|
||||||
|
|
||||||
|
data_node *before = NULL;
|
||||||
|
|
||||||
if (!after) {
|
if (!after) {
|
||||||
// change offset of all nodes already in the buffer
|
// change offset of all nodes already in the buffer
|
||||||
data_node *node = NULL;
|
data_node *node = NULL;
|
||||||
@@ -394,6 +420,8 @@ merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
node->offset += with->size;
|
node->offset += with->size;
|
||||||
|
if (before == NULL)
|
||||||
|
before = node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,13 +463,16 @@ merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
|
|||||||
list_add_item(&buffer->buffers, node);
|
list_add_item(&buffer->buffers, node);
|
||||||
node->offset = buffer->size;
|
node->offset = buffer->size;
|
||||||
} else
|
} else
|
||||||
list_add_link_to_head(&buffer->buffers, node);
|
list_insert_item_before(&buffer->buffers, before, node);
|
||||||
|
|
||||||
buffer->size += node->used;
|
buffer->size += node->used;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the data has been merged completely at this point
|
// the data has been merged completely at this point
|
||||||
free_buffer(with);
|
free_buffer(with);
|
||||||
|
|
||||||
|
//dprintf(" merge result:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,6 +511,7 @@ write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
data = (void *)((uint8 *)data + written);
|
||||||
|
|
||||||
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
@@ -520,6 +552,7 @@ read_data(net_buffer *_buffer, size_t offset, void *data, size_t size)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
data = (void *)((uint8 *)data + bytesRead);
|
||||||
|
|
||||||
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
@@ -536,6 +569,9 @@ prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
|||||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||||
data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
|
data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
|
||||||
|
|
||||||
|
TRACE(("prepend_size(buffer %p, size %ld)\n", buffer, size));
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
|
||||||
if (node->header_space < size) {
|
if (node->header_space < size) {
|
||||||
// we need to prepend a new buffer
|
// we need to prepend a new buffer
|
||||||
|
|
||||||
@@ -556,7 +592,15 @@ prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
|||||||
if (_contiguousBuffer)
|
if (_contiguousBuffer)
|
||||||
*_contiguousBuffer = node->start;
|
*_contiguousBuffer = node->start;
|
||||||
|
|
||||||
|
// adjust offset of following nodes
|
||||||
|
while ((node = (data_node *)list_get_next_item(&buffer->buffers, node)) != NULL) {
|
||||||
|
node->offset += size;
|
||||||
|
}
|
||||||
|
|
||||||
buffer->size += size;
|
buffer->size += size;
|
||||||
|
|
||||||
|
//dprintf(" prepend_size result:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +618,9 @@ prepend_data(net_buffer *buffer, const void *data, size_t size)
|
|||||||
else
|
else
|
||||||
write_data(buffer, 0, data, size);
|
write_data(buffer, 0, data, size);
|
||||||
|
|
||||||
|
//dprintf(" prepend result:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,6 +631,9 @@ append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
|||||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||||
data_node *node = (data_node *)list_get_last_item(&buffer->buffers);
|
data_node *node = (data_node *)list_get_last_item(&buffer->buffers);
|
||||||
|
|
||||||
|
TRACE(("append_size(buffer %p, size %ld)\n", buffer, size));
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
|
||||||
if (node->tail_space < size) {
|
if (node->tail_space < size) {
|
||||||
// we need to append a new buffer
|
// we need to append a new buffer
|
||||||
|
|
||||||
@@ -627,6 +677,8 @@ append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
|||||||
if (_contiguousBuffer)
|
if (_contiguousBuffer)
|
||||||
*_contiguousBuffer = NULL;
|
*_contiguousBuffer = NULL;
|
||||||
|
|
||||||
|
//dprintf(" append result 1:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,6 +690,9 @@ append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
|||||||
|
|
||||||
node->used += size;
|
node->used += size;
|
||||||
buffer->size += size;
|
buffer->size += size;
|
||||||
|
|
||||||
|
//dprintf(" append result 2:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,18 +727,39 @@ remove_header(net_buffer *_buffer, size_t bytes)
|
|||||||
if (bytes > buffer->size)
|
if (bytes > buffer->size)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
size_t left = bytes;
|
TRACE(("remove_header(buffer %p, %ld bytes)\n", buffer, bytes));
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
|
||||||
data_node *node = (data_node *)list_get_first_item(&buffer->buffers);
|
size_t left = bytes;
|
||||||
while (node != NULL && left > 0) {
|
data_node *node = NULL;
|
||||||
|
|
||||||
|
while (left >= 0) {
|
||||||
|
node = (data_node *)list_get_first_item(&buffer->buffers);
|
||||||
|
if (node == NULL) {
|
||||||
|
if (left == 0)
|
||||||
|
break;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->used > left)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// node will be removed completely
|
||||||
|
list_remove_item(&buffer->buffers, node);
|
||||||
|
left -= node->used;
|
||||||
|
remove_data_node(node);
|
||||||
|
node = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cut remaining node, if any
|
||||||
|
|
||||||
|
if (node != NULL) {
|
||||||
size_t cut = min_c(node->used, left);
|
size_t cut = min_c(node->used, left);
|
||||||
node->offset = 0;
|
node->offset = 0;
|
||||||
node->start += cut;
|
node->start += cut;
|
||||||
node->header_space += cut;
|
node->header_space += cut;
|
||||||
node->used -= cut;
|
node->used -= cut;
|
||||||
|
|
||||||
left -= cut;
|
|
||||||
|
|
||||||
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
node = (data_node *)list_get_next_item(&buffer->buffers, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -694,10 +770,23 @@ remove_header(net_buffer *_buffer, size_t bytes)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer->size -= bytes;
|
buffer->size -= bytes;
|
||||||
|
|
||||||
|
//dprintf(" remove result:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Removes bytes from the end of the buffer.
|
||||||
|
*/
|
||||||
|
static status_t
|
||||||
|
remove_trailer(net_buffer *buffer, size_t bytes)
|
||||||
|
{
|
||||||
|
return trim_data(buffer, buffer->size - bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Trims the buffer to the specified \a newSize by removing space from
|
Trims the buffer to the specified \a newSize by removing space from
|
||||||
the end of the buffer.
|
the end of the buffer.
|
||||||
@@ -706,6 +795,9 @@ static status_t
|
|||||||
trim_data(net_buffer *_buffer, size_t newSize)
|
trim_data(net_buffer *_buffer, size_t newSize)
|
||||||
{
|
{
|
||||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||||
|
TRACE(("trim_data(buffer %p, newSize = %ld, buffer size = %ld)\n",
|
||||||
|
buffer, newSize, buffer->size));
|
||||||
|
//dump_buffer(buffer);
|
||||||
|
|
||||||
if (newSize > buffer->size)
|
if (newSize > buffer->size)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -737,6 +829,9 @@ trim_data(net_buffer *_buffer, size_t newSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
buffer->size = newSize;
|
buffer->size = newSize;
|
||||||
|
|
||||||
|
//dprintf(" trim result:\n");
|
||||||
|
//dump_buffer(buffer);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,6 +850,8 @@ direct_access(net_buffer *_buffer, uint32 offset, size_t size,
|
|||||||
{
|
{
|
||||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||||
|
|
||||||
|
//TRACE(("direct_access(buffer %p, offset %ld, size %ld)\n", buffer, offset, size));
|
||||||
|
|
||||||
if (offset + size > buffer->size)
|
if (offset + size > buffer->size)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
@@ -906,7 +1003,7 @@ net_buffer_module_info gNetBufferModule = {
|
|||||||
NULL, // insert
|
NULL, // insert
|
||||||
NULL, // remove
|
NULL, // remove
|
||||||
remove_header,
|
remove_header,
|
||||||
NULL, // remove_trailer
|
remove_trailer,
|
||||||
trim_data,
|
trim_data,
|
||||||
|
|
||||||
NULL, // associate_data
|
NULL, // associate_data
|
||||||
|
|||||||
Reference in New Issue
Block a user