Added a simple net_buffer implementation (using a single malloc()ed
buffer) for debugging/testing purposes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25254 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
0e8836d284
commit
d96c90096f
@ -26,6 +26,9 @@ KernelAddon stack :
|
||||
stack.cpp
|
||||
stack_interface.cpp
|
||||
utility.cpp
|
||||
|
||||
# for test purposes
|
||||
#simple_net_buffer.cpp
|
||||
;
|
||||
|
||||
# Installation
|
||||
|
727
src/add-ons/kernel/network/stack/simple_net_buffer.cpp
Normal file
727
src/add-ons/kernel/network/stack/simple_net_buffer.cpp
Normal file
@ -0,0 +1,727 @@
|
||||
/*
|
||||
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Axel Dörfler, axeld@pinc-software.de
|
||||
* Ingo Weinhold, ingo_weinhold@gmx.de
|
||||
*/
|
||||
|
||||
#include "simple_net_buffer.h"
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
#include <net_buffer.h>
|
||||
#include <slab/Slab.h>
|
||||
#include <tracing.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <ByteOrder.h>
|
||||
#include <debug.h>
|
||||
#include <KernelExport.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "paranoia_config.h"
|
||||
|
||||
|
||||
//#define TRACE_BUFFER
|
||||
#ifdef TRACE_BUFFER
|
||||
# define TRACE(x) dprintf x
|
||||
#else
|
||||
# define TRACE(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
#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 : simple_net_buffer {
|
||||
ancillary_data_list ancillary_data;
|
||||
};
|
||||
|
||||
|
||||
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 remove_header(net_buffer *_buffer, size_t bytes);
|
||||
static status_t remove_trailer(net_buffer *_buffer, size_t bytes);
|
||||
|
||||
|
||||
static void
|
||||
copy_metadata(net_buffer *destination, const net_buffer *source)
|
||||
{
|
||||
memcpy(destination->source, source->source,
|
||||
min_c(source->source->sa_len, sizeof(sockaddr_storage)));
|
||||
memcpy(destination->destination, source->destination,
|
||||
min_c(source->destination->sa_len, sizeof(sockaddr_storage)));
|
||||
|
||||
destination->flags = source->flags;
|
||||
destination->interface = source->interface;
|
||||
destination->offset = source->offset;
|
||||
destination->size = source->size;
|
||||
destination->protocol = source->protocol;
|
||||
destination->type = source->type;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - module API
|
||||
|
||||
|
||||
static net_buffer *
|
||||
create_buffer(size_t headerSpace)
|
||||
{
|
||||
net_buffer_private *buffer = new(nothrow) net_buffer_private;
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
TRACE(("%ld: create buffer %p\n", find_thread(NULL), buffer));
|
||||
|
||||
buffer->data = NULL;
|
||||
new(&buffer->ancillary_data) ancillary_data_list;
|
||||
|
||||
buffer->source = (sockaddr *)&buffer->storage.source;
|
||||
buffer->destination = (sockaddr *)&buffer->storage.destination;
|
||||
|
||||
buffer->storage.source.ss_len = 0;
|
||||
buffer->storage.destination.ss_len = 0;
|
||||
|
||||
buffer->interface = NULL;
|
||||
buffer->offset = 0;
|
||||
buffer->flags = 0;
|
||||
buffer->size = 0;
|
||||
|
||||
buffer->type = -1;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
free_buffer(net_buffer *_buffer)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
free(buffer->data);
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
|
||||
/*! Creates a duplicate of the \a buffer. The new buffer does not share internal
|
||||
storage; they are completely independent from each other.
|
||||
*/
|
||||
static net_buffer *
|
||||
duplicate_buffer(net_buffer *_buffer)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
net_buffer* duplicate = create_buffer(0);
|
||||
if (duplicate == NULL)
|
||||
return NULL;
|
||||
|
||||
if (append_data(duplicate, buffer->data, buffer->size) != B_OK) {
|
||||
free_buffer(duplicate);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
copy_metadata(duplicate, buffer);
|
||||
|
||||
return duplicate;
|
||||
}
|
||||
|
||||
|
||||
/*! Clones the buffer by grabbing another reference to the underlying data.
|
||||
If that data changes, it will be changed in the clone as well.
|
||||
|
||||
If \a shareFreeSpace is \c true, the cloned buffer may claim the free
|
||||
space in the original buffer as the original buffer can still do. If you
|
||||
are using this, it's your responsibility that only one of the buffers
|
||||
will do this.
|
||||
*/
|
||||
static net_buffer *
|
||||
clone_buffer(net_buffer *_buffer, bool shareFreeSpace)
|
||||
{
|
||||
return duplicate_buffer(_buffer);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Split the buffer at offset, the header data
|
||||
is returned as new buffer.
|
||||
TODO: optimize and avoid making a copy.
|
||||
*/
|
||||
static net_buffer *
|
||||
split_buffer(net_buffer *_from, uint32 offset)
|
||||
{
|
||||
net_buffer_private *from = (net_buffer_private *)_from;
|
||||
|
||||
if (offset > from->size)
|
||||
return NULL;
|
||||
|
||||
net_buffer_private* buffer = (net_buffer_private*)create_buffer(0);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
|
||||
// allocate space for the tail data
|
||||
size_t remaining = from->size - offset;
|
||||
uint8* tailData = (uint8*)malloc(remaining);
|
||||
if (tailData == NULL) {
|
||||
free_buffer(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(tailData, from->data + offset, remaining);
|
||||
|
||||
// truncate original data and move it to the new buffer
|
||||
buffer->data = (uint8*)realloc(from->data, offset);
|
||||
buffer->size = offset;
|
||||
|
||||
// the old buffer gets the newly allocated tail data
|
||||
from->data = tailData;
|
||||
from->size = remaining;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Merges the second buffer with the first. If \a after is \c true, the
|
||||
second buffer's contents will be appended to the first ones, else they
|
||||
will be prepended.
|
||||
The second buffer will be freed if this function succeeds.
|
||||
*/
|
||||
static status_t
|
||||
merge_buffer(net_buffer *_buffer, net_buffer *_with, bool after)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
net_buffer_private *with = (net_buffer_private *)_with;
|
||||
if (with == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (after) {
|
||||
// the simple case: just append the second buffer
|
||||
status_t error = append_data(buffer, with->data, with->size);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
} else {
|
||||
// append buffer to the second buffer, then switch the data
|
||||
status_t error = append_data(with, buffer->data, buffer->size);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
free(buffer->data);
|
||||
buffer->data = with->data;
|
||||
buffer->size = with->size;
|
||||
|
||||
with->data = NULL;
|
||||
}
|
||||
|
||||
free_buffer(with);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*! Writes into existing allocated memory.
|
||||
\return B_BAD_VALUE if you write outside of the buffers current
|
||||
bounds.
|
||||
*/
|
||||
static status_t
|
||||
write_data(net_buffer *_buffer, size_t offset, const void *data, size_t size)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (offset + size > buffer->size)
|
||||
return B_BAD_VALUE;
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
memcpy(buffer->data + offset, data, size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
read_data(net_buffer *_buffer, size_t offset, void *data, size_t size)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (offset + size > buffer->size)
|
||||
return B_BAD_VALUE;
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
memcpy(data, buffer->data + offset, size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
prepend_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
||||
{
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
uint8* newData = (uint8*)malloc(buffer->size + size);
|
||||
if (newData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memcpy(newData + size, buffer->data, buffer->size);
|
||||
|
||||
free(buffer->data);
|
||||
buffer->data = newData;
|
||||
buffer->size += size;
|
||||
|
||||
if (_contiguousBuffer != NULL)
|
||||
*_contiguousBuffer = buffer->data;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
prepend_data(net_buffer *buffer, const void *data, size_t size)
|
||||
{
|
||||
status_t status = prepend_size(buffer, size, NULL);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
write_data(buffer, 0, data, size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
append_size(net_buffer *_buffer, size_t size, void **_contiguousBuffer)
|
||||
{
|
||||
if (size == 0)
|
||||
return B_OK;
|
||||
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
uint8* newData = (uint8*)realloc(buffer->data, buffer->size + size);
|
||||
if (newData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (_contiguousBuffer != NULL)
|
||||
*_contiguousBuffer = newData + buffer->size;
|
||||
|
||||
buffer->data = newData;
|
||||
buffer->size += size;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
append_data(net_buffer *buffer, const void *data, size_t size)
|
||||
{
|
||||
size_t used = buffer->size;
|
||||
|
||||
status_t status = append_size(buffer, size, NULL);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
write_data(buffer, used, data, size);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Removes bytes from the beginning of the buffer.
|
||||
*/
|
||||
static status_t
|
||||
remove_header(net_buffer *_buffer, size_t bytes)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (bytes > buffer->size)
|
||||
return B_BAD_VALUE;
|
||||
if (bytes == 0)
|
||||
return B_OK;
|
||||
|
||||
buffer->size -= bytes;
|
||||
memmove(buffer->data, buffer->data + bytes, buffer->size);
|
||||
buffer->data = (uint8*)realloc(buffer->data, buffer->size);
|
||||
|
||||
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
|
||||
the end of the buffer.
|
||||
*/
|
||||
static status_t
|
||||
trim_data(net_buffer *_buffer, size_t newSize)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (newSize > buffer->size)
|
||||
return B_BAD_VALUE;
|
||||
if (newSize == buffer->size)
|
||||
return B_OK;
|
||||
|
||||
buffer->data = (uint8*)realloc(buffer->data, newSize);
|
||||
buffer->size = newSize;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Appends data coming from buffer \a source to the buffer \a buffer. It only
|
||||
clones the data, though, that is the data is not copied, just referenced.
|
||||
*/
|
||||
static status_t
|
||||
append_cloned_data(net_buffer *_buffer, net_buffer *_source, uint32 offset,
|
||||
size_t bytes)
|
||||
{
|
||||
if (bytes == 0)
|
||||
return B_OK;
|
||||
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
net_buffer_private *source = (net_buffer_private *)_source;
|
||||
|
||||
if (offset + bytes > source->size)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return append_data(buffer, source->data + offset, bytes);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
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
|
||||
to that space into \a _contiguousBuffer.
|
||||
|
||||
\return B_BAD_VALUE if the offset is outside of the buffer's bounds.
|
||||
\return B_ERROR in case the buffer is not contiguous at that location.
|
||||
*/
|
||||
static status_t
|
||||
direct_access(net_buffer *_buffer, uint32 offset, size_t size,
|
||||
void **_contiguousBuffer)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (offset + size > buffer->size)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
*_contiguousBuffer = buffer->data + offset;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
checksum_data(net_buffer *_buffer, uint32 offset, size_t size, bool finalize)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
if (offset + size > buffer->size || size == 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint16 sum = compute_checksum(buffer->data + offset, size);
|
||||
if ((offset & 1) != 0) {
|
||||
// if we're at an uneven offset, we have to swap the checksum
|
||||
sum = __swap_int16(sum);
|
||||
}
|
||||
|
||||
if (!finalize)
|
||||
return (uint16)sum;
|
||||
|
||||
return (uint16)~sum;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
get_iovecs(net_buffer *_buffer, struct iovec *iovecs, uint32 vecCount)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
iovecs[0].iov_base = buffer->data;
|
||||
iovecs[0].iov_len = buffer->size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static uint32
|
||||
count_iovecs(net_buffer *_buffer)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
swap_addresses(net_buffer *buffer)
|
||||
{
|
||||
std::swap(buffer->source, buffer->destination);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dump_buffer(net_buffer *_buffer)
|
||||
{
|
||||
net_buffer_private *buffer = (net_buffer_private *)_buffer;
|
||||
|
||||
dprintf("buffer %p, size %ld, data: %p\n", buffer, buffer->size,
|
||||
buffer->data);
|
||||
dump_block((char*)buffer->data, min_c(buffer->size, 32), " ");
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
return B_OK;
|
||||
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
net_buffer_module_info gSimpleNetBufferModule = {
|
||||
//net_buffer_module_info gNetBufferModule = {
|
||||
{
|
||||
NET_BUFFER_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
create_buffer,
|
||||
free_buffer,
|
||||
|
||||
duplicate_buffer,
|
||||
clone_buffer,
|
||||
split_buffer,
|
||||
merge_buffer,
|
||||
|
||||
prepend_size,
|
||||
prepend_data,
|
||||
append_size,
|
||||
append_data,
|
||||
NULL, // insert
|
||||
NULL, // remove
|
||||
remove_header,
|
||||
remove_trailer,
|
||||
trim_data,
|
||||
append_cloned_data,
|
||||
|
||||
NULL, // associate_data
|
||||
|
||||
attach_ancillary_data,
|
||||
detach_ancillary_data,
|
||||
transfer_ancillary_data,
|
||||
next_ancillary_data,
|
||||
|
||||
direct_access,
|
||||
read_data,
|
||||
write_data,
|
||||
|
||||
checksum_data,
|
||||
|
||||
NULL, // get_memory_map
|
||||
get_iovecs,
|
||||
count_iovecs,
|
||||
|
||||
swap_addresses,
|
||||
|
||||
dump_buffer, // dump
|
||||
};
|
||||
|
24
src/add-ons/kernel/network/stack/simple_net_buffer.h
Normal file
24
src/add-ons/kernel/network/stack/simple_net_buffer.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SIMPLE_NET_BUFFER_H
|
||||
#define SIMPLE_NET_BUFFER_H
|
||||
|
||||
#include <net_buffer.h>
|
||||
|
||||
|
||||
struct simple_net_buffer : net_buffer {
|
||||
uint8* data;
|
||||
|
||||
struct {
|
||||
struct sockaddr_storage source;
|
||||
struct sockaddr_storage destination;
|
||||
} storage;
|
||||
};
|
||||
|
||||
|
||||
extern net_buffer_module_info gSimpleNetBufferModule;
|
||||
|
||||
|
||||
#endif // SIMPLE_NET_BUFFER_H
|
Loading…
Reference in New Issue
Block a user