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:
Axel Dörfler
2006-10-15 01:12:54 +00:00
parent ed013acf90
commit 2e95d2f425
+115 -18
View File
@@ -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