Added support for attaching ancillary data to a net_buffer. It's a naive

implementation ATM, since it malloc()s the required memory.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24940 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-04-12 09:19:44 +00:00
parent 5f2d64a25e
commit 62d7da1f45
2 changed files with 207 additions and 2 deletions

View File

@ -37,6 +37,12 @@ typedef struct net_buffer {
uint8 protocol;
} net_buffer;
typedef struct ancillary_data_header {
int level;
int type;
size_t len;
} ancillary_data_header;
struct net_buffer_module_info {
module_info info;
@ -68,6 +74,17 @@ struct net_buffer_module_info {
status_t (*associate_data)(net_buffer *buffer, void *data);
status_t (*attach_ancillary_data)(net_buffer *buffer,
const ancillary_data_header *header, const void *data,
void (*destructor)(const ancillary_data_header*, void*),
void **_allocatedData);
status_t (*detach_ancillary_data)(net_buffer *buffer, void *data,
bool destroy);
void * (*transfer_ancillary_data)(net_buffer *from,
net_buffer *to);
void * (*next_ancillary_data)(net_buffer *buffer,
void *previousData, ancillary_data_header *_header);
status_t (*direct_access)(net_buffer *buffer, uint32 offset,
size_t bytes, void **_data);
status_t (*read)(net_buffer *buffer, uint32 offset, void *data,

View File

@ -16,6 +16,7 @@
#include <ByteOrder.h>
#include <KernelExport.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <algorithm>
#include <stdlib.h>
@ -58,11 +59,31 @@ struct data_header {
data_node *first_node;
};
#define MAX_ANCILLARY_DATA_SIZE 128
struct ancillary_data : DoublyLinkedListLinkImpl<ancillary_data> {
void* Data()
{
return (char*)this + _ALIGN(sizeof(ancillary_data));
}
static ancillary_data* FromData(void* data)
{
return (ancillary_data*)((char*)data - _ALIGN(sizeof(ancillary_data)));
}
ancillary_data_header header;
void (*destructor)(const ancillary_data_header*, void*);
};
typedef DoublyLinkedList<ancillary_data> ancillary_data_list;
#define MAX_FREE_BUFFER_SIZE (BUFFER_SIZE - sizeof(data_header))
struct net_buffer_private : net_buffer {
struct list buffers;
data_node first_node;
struct list buffers;
data_node first_node;
ancillary_data_list ancillary_data;
struct {
struct sockaddr_storage source;
@ -353,6 +374,8 @@ create_buffer(size_t headerSpace)
list_init(&buffer->buffers);
list_add_item(&buffer->buffers, &buffer->first_node);
new(&buffer->ancillary_data) ancillary_data_list;
buffer->source = (sockaddr *)&buffer->storage.source;
buffer->destination = (sockaddr *)&buffer->storage.destination;
@ -382,6 +405,12 @@ free_buffer(net_buffer *_buffer)
remove_data_node(node);
}
while (ancillary_data* data = buffer->ancillary_data.RemoveHead()) {
if (data->destructor != NULL)
data->destructor(&data->header, data->Data());
free(data);
}
free_net_buffer(buffer);
}
@ -1067,6 +1096,160 @@ append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
}
/*!
Attaches ancillary data to the given buffer. The data are completely
orthogonal to the data the buffer stores.
\param buffer The buffer.
\param header Description of the data.
\param data If not \c NULL, the data are copied into the allocated storage.
\param destructor If not \c NULL, this function will be invoked with the
data as parameter when the buffer is destroyed.
\param _allocatedData Will be set to the storage allocated for the data.
\return \c B_OK when everything goes well, another error code otherwise.
*/
static status_t
attach_ancillary_data(net_buffer *_buffer, const ancillary_data_header *header,
const void *data, void (*destructor)(const ancillary_data_header*, void*),
void **_allocatedData)
{
// TODO: Obviously it would be nice to allocate the memory for the
// ancillary data in the buffer.
net_buffer_private *buffer = (net_buffer_private *)_buffer;
// check parameters
if (header == NULL)
return B_BAD_VALUE;
if (header->len > MAX_ANCILLARY_DATA_SIZE)
return ENOBUFS;
// allocate buffer
void *dataBuffer = malloc(_ALIGN(sizeof(ancillary_data)) + header->len);
if (dataBuffer == NULL)
return B_NO_MEMORY;
// init and attach the structure
ancillary_data *ancillaryData = new(dataBuffer) ancillary_data;
ancillaryData->header = *header;
ancillaryData->destructor = destructor;
buffer->ancillary_data.Add(ancillaryData);
if (data != NULL)
memcpy(ancillaryData->Data(), data, header->len);
if (_allocatedData != NULL)
*_allocatedData = ancillaryData->Data();
return B_OK;
}
/*!
Detaches ancillary data from the given buffer. The associated memory is
free, i.e. the \a data pointer must no longer be used after calling this
function. Depending on \a destroy, the destructor is invoked before freeing
the data.
\param buffer The buffer.
\param data Pointer to the data to be removed (as returned by
attach_ancillary_data() or next_ancillary_data()).
\param destroy If \c true, the destructor, if one was passed to
attach_ancillary_data(), is invoked for the data.
\return \c B_OK when everything goes well, another error code otherwise.
*/
static status_t
detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
{
net_buffer_private *buffer = (net_buffer_private *)_buffer;
if (data == NULL)
return B_BAD_VALUE;
ancillary_data *ancillaryData = ancillary_data::FromData(data);
buffer->ancillary_data.Remove(ancillaryData);
if (destroy && ancillaryData->destructor != NULL) {
ancillaryData->destructor(&ancillaryData->header,
ancillaryData->Data());
}
free(ancillaryData);
return B_OK;
}
/*!
Moves all ancillary data from buffer \c from to the end of the list of
ancillary data of buffer \c to. Note, that this is the only function that
transfers or copies ancillary data from one buffer to another.
\param from The buffer from which to remove the ancillary data.
\param to The buffer to which to add teh ancillary data.
\return A pointer to the first of the moved ancillary data, if any, \c NULL
otherwise.
*/
static void *
transfer_ancillary_data(net_buffer *_from, net_buffer *_to)
{
net_buffer_private *from = (net_buffer_private *)_from;
net_buffer_private *to = (net_buffer_private *)_to;
if (from == NULL || to == NULL)
return NULL;
ancillary_data *ancillaryData = from->ancillary_data.Head();
to->ancillary_data.MoveFrom(&from->ancillary_data);
return ancillaryData != NULL ? ancillaryData->Data() : NULL;
}
/*!
Returns the next ancillary data. When iterating over the data, initially
a \c NULL pointer shall be passed as \a previousData, subsequently the
previously returned data pointer. After the last item, \c NULL is returned.
Note, that it is not safe to call detach_ancillary_data() for a data item
and then pass that pointer to this function. First get the next item, then
detach the previous one.
\param buffer The buffer.
\param previousData The pointer to the previous data returned by this
function. Initially \c NULL shall be passed.
\param header Pointer to allocated storage into which the data description
is written. May be \c NULL.
\return A pointer to the next ancillary data in the buffer. \c NULL after
the last one.
*/
static void*
next_ancillary_data(net_buffer *_buffer, void *previousData,
ancillary_data_header *_header)
{
net_buffer_private *buffer = (net_buffer_private *)_buffer;
ancillary_data *ancillaryData;
if (previousData == NULL) {
ancillaryData = buffer->ancillary_data.Head();
} else {
ancillaryData = ancillary_data::FromData(previousData);
ancillaryData = buffer->ancillary_data.GetNext(ancillaryData);
}
if (ancillaryData == NULL)
return NULL;
if (_header != NULL)
*_header = ancillaryData->header;
return ancillaryData->Data();
}
/*!
Tries to directly access the requested space in the buffer.
If the space is contiguous, the function will succeed and place a pointer
@ -1257,6 +1440,11 @@ net_buffer_module_info gNetBufferModule = {
NULL, // associate_data
attach_ancillary_data,
detach_ancillary_data,
transfer_ancillary_data,
next_ancillary_data,
direct_access,
read_data,
write_data,