Moved the container management for ancillary data from the net_buffer

module to the stack module. There's a dedicated struct
ancillary_data_container, now. One can just set the container on a
net_buffer.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25292 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold 2008-05-02 14:37:16 +00:00
parent 110d4031fb
commit 49e00d1f99
10 changed files with 332 additions and 185 deletions

View File

@ -37,11 +37,7 @@ typedef struct net_buffer {
uint8 protocol;
} net_buffer;
typedef struct ancillary_data_header {
int level;
int type;
size_t len;
} ancillary_data_header;
struct ancillary_data_container;
struct net_buffer_module_info {
module_info info;
@ -74,16 +70,11 @@ 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 (*set_ancillary_data)(net_buffer *buffer,
ancillary_data_container *container);
ancillary_data_container* (*get_ancillary_data)(net_buffer *buffer);
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);

View File

@ -16,6 +16,9 @@
#define LEVEL_DRIVER_IOCTL 0x0f000000
#define LEVEL_MASK 0x0fffffff
struct ancillary_data_container;
struct ancillary_data_header;
typedef struct net_protocol {
struct net_protocol *next;
struct net_protocol_module_info *module;
@ -69,8 +72,8 @@ struct net_protocol_module_info {
status_t (*error_reply)(net_protocol *self, net_buffer *causedError,
uint32 code, void *errorData);
status_t (*attach_ancillary_data)(net_protocol *self, net_buffer *buffer,
const cmsghdr *header);
status_t (*add_ancillary_data)(net_protocol *self,
ancillary_data_container *container, const cmsghdr *header);
ssize_t (*process_ancillary_data)(net_protocol *self,
const ancillary_data_header *header, const void *data,
void *buffer, size_t bufferSize);

View File

@ -24,6 +24,8 @@ struct net_domain;
struct net_socket;
struct net_timer;
typedef struct ancillary_data_container ancillary_data_container;
struct net_fifo {
benaphore lock;
sem_id notify;
@ -64,6 +66,12 @@ struct net_device_monitor {
void (*event)(struct net_device_monitor *monitor, int32 event);
};
typedef struct ancillary_data_header {
int level;
int type;
size_t len;
} ancillary_data_header;
struct net_stack_module_info {
module_info info;
@ -139,6 +147,21 @@ struct net_stack_module_info {
bool (*is_restarted_syscall)(void);
void (*store_syscall_restart_timeout)(bigtime_t timeout);
bigtime_t (*restore_syscall_restart_timeout)(void);
// ancillary data
ancillary_data_container* (*create_ancillary_data_container)();
void (*delete_ancillary_data_container)(
ancillary_data_container* container);
status_t (*add_ancillary_data)(ancillary_data_container *container,
const ancillary_data_header *header, const void *data,
void (*destructor)(const ancillary_data_header*, void*),
void **_allocatedData);
status_t (*remove_ancillary_data)(ancillary_data_container *container,
void *data, bool destroy);
void* (*move_ancillary_data)(ancillary_data_container *from,
ancillary_data_container *to);
void* (*next_ancillary_data)(ancillary_data_container *container,
void *previousData, ancillary_data_header *_header);
};
#endif // NET_STACK_H

View File

@ -268,11 +268,11 @@ unix_error_reply(net_protocol *protocol, net_buffer *causedError, uint32 code,
status_t
unix_attach_ancillary_data(net_protocol *self, net_buffer *buffer,
unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container,
const cmsghdr *header)
{
TRACE("[%ld] unix_attach_ancillary_data(%p, %p, %p (level: %d, type: %d, "
"len: %d))\n", find_thread(NULL), self, buffer, header,
TRACE("[%ld] unix_add_ancillary_data(%p, %p, %p (level: %d, type: %d, "
"len: %d))\n", find_thread(NULL), self, container, header,
header->cmsg_level, header->cmsg_type, (int)header->cmsg_len);
// we support only SCM_RIGHTS
@ -302,17 +302,17 @@ unix_attach_ancillary_data(net_protocol *self, net_buffer *buffer,
}
}
// attach the ancillary data to the buffer
// attach the ancillary data to the container
if (error == B_OK) {
ancillary_data_header header;
header.level = SOL_SOCKET;
header.type = SCM_RIGHTS;
header.len = count * sizeof(file_descriptor*);
TRACE("[%ld] unix_attach_ancillary_data(): attaching %d FDs to "
"buffer\n", find_thread(NULL), count);
TRACE("[%ld] unix_add_ancillary_data(): adding %d FDs to "
"container\n", find_thread(NULL), count);
error = gBufferModule->attach_ancillary_data(buffer, &header,
error = gStackModule->add_ancillary_data(container, &header,
descriptors, destroy_scm_rights_descriptors, NULL);
}
@ -468,7 +468,7 @@ net_protocol_module_info gUnixModule = {
unix_deliver_data,
unix_error,
unix_error_reply,
unix_attach_ancillary_data,
unix_add_ancillary_data,
unix_process_ancillary_data
};

View File

@ -15,6 +15,7 @@ UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
UsePrivateHeaders net ;
KernelAddon stack :
ancillary_data.cpp
datalink.cpp
domains.cpp
interfaces.cpp

View File

@ -0,0 +1,203 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "ancillary_data.h"
#include <stdlib.h>
#include <string.h>
#include <new>
#include <util/DoublyLinkedList.h>
#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;
struct ancillary_data_container {
ancillary_data_list data_list;
};
ancillary_data_container*
create_ancillary_data_container()
{
return new(std::nothrow) ancillary_data_container;
}
void
delete_ancillary_data_container(ancillary_data_container* container)
{
if (container == NULL)
return;
while (ancillary_data* data = container->data_list.RemoveHead()) {
if (data->destructor != NULL)
data->destructor(&data->header, data->Data());
free(data);
}
}
/*!
Adds ancillary data to the given container.
\param container The container.
\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 container 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.
*/
status_t
add_ancillary_data(ancillary_data_container* container,
const ancillary_data_header* header, const void* data,
void (*destructor)(const ancillary_data_header*, void*),
void** _allocatedData)
{
// 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;
container->data_list.Add(ancillaryData);
if (data != NULL)
memcpy(ancillaryData->Data(), data, header->len);
if (_allocatedData != NULL)
*_allocatedData = ancillaryData->Data();
return B_OK;
}
/*!
Removes ancillary data from the given container. The associated memory is
freed, 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 container The container.
\param data Pointer to the data to be removed (as returned by
add_ancillary_data() or next_ancillary_data()).
\param destroy If \c true, the destructor, if one was passed to
add_ancillary_data(), is invoked for the data.
\return \c B_OK when everything goes well, another error code otherwise.
*/
status_t
remove_ancillary_data(ancillary_data_container* container, void* data,
bool destroy)
{
if (data == NULL)
return B_BAD_VALUE;
ancillary_data *ancillaryData = ancillary_data::FromData(data);
container->data_list.Remove(ancillaryData);
if (destroy && ancillaryData->destructor != NULL) {
ancillaryData->destructor(&ancillaryData->header,
ancillaryData->Data());
}
free(ancillaryData);
return B_OK;
}
/*!
Moves all ancillary data from container \c from to the end of the list of
ancillary data of container \c to.
\param from The container from which to remove the ancillary data.
\param to The container to which to add the ancillary data.
\return A pointer to the first of the moved ancillary data, if any, \c NULL
otherwise.
*/
void *
move_ancillary_data(ancillary_data_container* from,
ancillary_data_container* to)
{
if (from == NULL || to == NULL)
return NULL;
ancillary_data *ancillaryData = from->data_list.Head();
to->data_list.MoveFrom(&from->data_list);
return ancillaryData != NULL ? ancillaryData->Data() : NULL;
}
/*!
Returns the next ancillary data. When iterating through 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 remove_ancillary_data() for a data item
and then pass that pointer to this function. First get the next item, then
remove the previous one.
\param container The container.
\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 container. \c NULL after
the last one.
*/
void*
next_ancillary_data(ancillary_data_container* container, void* previousData,
ancillary_data_header* _header)
{
ancillary_data *ancillaryData;
if (previousData == NULL) {
ancillaryData = container->data_list.Head();
} else {
ancillaryData = ancillary_data::FromData(previousData);
ancillaryData = container->data_list.GetNext(ancillaryData);
}
if (ancillaryData == NULL)
return NULL;
if (_header != NULL)
*_header = ancillaryData->header;
return ancillaryData->Data();
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef NET_ANCILLARY_DATA_H
#define NET_ANCILLARY_DATA_H
#include <net_stack.h>
struct ancillary_data_container;
ancillary_data_container* create_ancillary_data_container();
void delete_ancillary_data_container(ancillary_data_container* container);
status_t add_ancillary_data(ancillary_data_container* container,
const ancillary_data_header* header, const void* data,
void (*destructor)(const ancillary_data_header*, void*),
void** _allocatedData);
status_t remove_ancillary_data(ancillary_data_container* container, void* data,
bool destroy);
void* move_ancillary_data(ancillary_data_container* from,
ancillary_data_container* to);
void* next_ancillary_data(ancillary_data_container* container,
void* previousData, ancillary_data_header* _header);
#endif // NET_ANCILLARY_DATA_H

View File

@ -25,6 +25,8 @@
#include <sys/param.h>
#include <sys/uio.h>
#include "ancillary_data.h"
#include "paranoia_config.h"
@ -121,30 +123,11 @@ struct data_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;
struct net_buffer_private : net_buffer {
struct list buffers;
data_header *allocation_header; // the current place where we
// allocate header space (nodes,...)
ancillary_data_list ancillary_data;
ancillary_data_container* ancillary_data;
struct {
struct sockaddr_storage source;
@ -1021,7 +1004,7 @@ create_buffer(size_t headerSpace)
list_init(&buffer->buffers);
list_add_item(&buffer->buffers, node);
new(&buffer->ancillary_data) ancillary_data_list;
buffer->ancillary_data = NULL;
buffer->source = (sockaddr *)&buffer->storage.source;
buffer->destination = (sockaddr *)&buffer->storage.destination;
@ -1063,11 +1046,7 @@ 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);
}
delete_ancillary_data_container(buffer->ancillary_data);
release_data_header(buffer->allocation_header);
@ -1873,89 +1852,17 @@ 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)
void
set_ancillary_data(net_buffer *buffer, ancillary_data_container *container)
{
// 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;
((net_buffer_private*)buffer)->ancillary_data = container;
}
/*!
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)
ancillary_data_container*
get_ancillary_data(net_buffer *buffer)
{
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;
return ((net_buffer_private*)buffer)->ancillary_data;
}
@ -1965,7 +1872,7 @@ detach_ancillary_data(net_buffer *_buffer, void *data, bool destroy)
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.
\param to The buffer to which to add the ancillary data.
\return A pointer to the first of the moved ancillary data, if any, \c NULL
otherwise.
*/
@ -1978,52 +1885,23 @@ transfer_ancillary_data(net_buffer *_from, net_buffer *_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)
if (from->ancillary_data == NULL)
return NULL;
if (_header != NULL)
*_header = ancillaryData->header;
if (to->ancillary_data == NULL) {
// no ancillary data in the target buffer
to->ancillary_data = from->ancillary_data;
from->ancillary_data = NULL;
return next_ancillary_data(to->ancillary_data, NULL, NULL);
}
return ancillaryData->Data();
// both have ancillary data
void *data = move_ancillary_data(from->ancillary_data,
to->ancillary_data);
delete_ancillary_data_container(from->ancillary_data);
from->ancillary_data = NULL;
return data;
}
@ -2228,10 +2106,9 @@ net_buffer_module_info gNetBufferModule = {
NULL, // associate_data
attach_ancillary_data,
detach_ancillary_data,
set_ancillary_data,
get_ancillary_data,
transfer_ancillary_data,
next_ancillary_data,
direct_access,
read_data,

View File

@ -30,6 +30,7 @@
#include <net_stack.h>
#include <net_stat.h>
#include "ancillary_data.h"
#include "utility.h"
@ -134,8 +135,8 @@ err1:
static status_t
attach_ancillary_data(net_socket *socket, net_buffer *buffer, void *data,
size_t dataLen)
add_ancillary_data(net_socket *socket, ancillary_data_container* container,
void *data, size_t dataLen)
{
cmsghdr *header = (cmsghdr*)data;
@ -143,11 +144,11 @@ attach_ancillary_data(net_socket *socket, net_buffer *buffer, void *data,
if (header->cmsg_len < sizeof(cmsghdr) || header->cmsg_len > dataLen)
return B_BAD_VALUE;
if (socket->first_info->attach_ancillary_data == NULL)
if (socket->first_info->add_ancillary_data == NULL)
return EOPNOTSUPP;
status_t status = socket->first_info->attach_ancillary_data(
socket->first_protocol, buffer, header);
status_t status = socket->first_info->add_ancillary_data(
socket->first_protocol, container, header);
if (status != B_OK)
return status;
@ -160,17 +161,20 @@ attach_ancillary_data(net_socket *socket, net_buffer *buffer, void *data,
static status_t
process_ancillary_data(net_socket *socket, net_buffer *buffer, msghdr *_header)
process_ancillary_data(net_socket *socket, ancillary_data_container* container,
msghdr *_header)
{
if (container == NULL)
return B_OK;
uint8 *dataBuffer = (uint8*)_header->msg_control;
int dataBufferLen = _header->msg_controllen;
ancillary_data_header header;
void *data = NULL;
while ((data = gNetBufferModule.next_ancillary_data(buffer, data, &header))
!= NULL) {
while ((data = next_ancillary_data(container, data, &header)) != NULL) {
if (socket->first_info->process_ancillary_data == NULL)
return EOPNOTSUPP;
@ -943,7 +947,8 @@ socket_receive(net_socket *socket, msghdr *header, void *data, size_t length,
// process ancillary data
if (header != NULL) {
if (buffer != NULL && header->msg_control != NULL) {
status = process_ancillary_data(socket, buffer, header);
status = process_ancillary_data(socket,
gNetBufferModule.get_ancillary_data(buffer), header);
if (status != B_OK) {
gNetBufferModule.free(buffer);
return status;
@ -1129,8 +1134,15 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length,
// attach ancillary data to the first buffer
status_t status = B_OK;
if (ancillaryData != NULL) {
status = attach_ancillary_data(socket, buffer, ancillaryData,
ancillaryDataLen);
ancillary_data_container *container
= create_ancillary_data_container();
if (container != NULL) {
gNetBufferModule.set_ancillary_data(buffer, container);
status = add_ancillary_data(socket, container, ancillaryData,
ancillaryDataLen);
} else
status = B_NO_MEMORY;
ancillaryData = NULL;
}

View File

@ -7,6 +7,7 @@
*/
#include "ancillary_data.h"
#include "domains.h"
#include "interfaces.h"
#include "link.h"
@ -922,6 +923,13 @@ net_stack_module_info gNetStackModule = {
is_restarted_syscall,
store_syscall_restart_timeout,
restore_syscall_restart_timeout,
create_ancillary_data_container,
delete_ancillary_data_container,
add_ancillary_data,
remove_ancillary_data,
move_ancillary_data,
next_ancillary_data
};
module_info *modules[] = {