* Added optional {send,read}_data_no_buffer() hooks to the protocol

module interface. They directly operate on iovecs and thus allow
  protocols that don't need it to avoid the creation of a net_buffer.
* Adjusted the socket module to support the new hooks. If they are
  present, they will be chosen over the old hooks.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25299 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-05-03 01:11:21 +00:00
parent 3134e71811
commit cdc00dadfc
3 changed files with 106 additions and 44 deletions
+9
View File
@@ -19,6 +19,8 @@
struct ancillary_data_container; struct ancillary_data_container;
struct ancillary_data_header; struct ancillary_data_header;
struct iovec;
typedef struct net_protocol { typedef struct net_protocol {
struct net_protocol *next; struct net_protocol *next;
struct net_protocol_module_info *module; struct net_protocol_module_info *module;
@@ -77,6 +79,13 @@ struct net_protocol_module_info {
ssize_t (*process_ancillary_data)(net_protocol *self, ssize_t (*process_ancillary_data)(net_protocol *self,
const ancillary_data_header *header, const void *data, const ancillary_data_header *header, const void *data,
void *buffer, size_t bufferSize); void *buffer, size_t bufferSize);
ssize_t (*send_data_no_buffer)(net_protocol *self, const iovec *vecs,
size_t vecCount, ancillary_data_container *ancillaryData,
const struct sockaddr *address, socklen_t addressLength);
ssize_t (*read_data_no_buffer)(net_protocol *self, const iovec *vecs,
size_t vecCount, ancillary_data_container **_ancillaryData,
struct sockaddr *_address, socklen_t *_addressLength);
}; };
#endif // NET_PROTOCOL_H #endif // NET_PROTOCOL_H
+1 -1
View File
@@ -12,7 +12,7 @@ if $(TARGET_PLATFORM) != haiku {
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
UsePrivateHeaders net ; UsePrivateHeaders net shared ;
KernelAddon stack : KernelAddon stack :
ancillary_data.cpp ancillary_data.cpp
+96 -43
View File
@@ -16,6 +16,7 @@
#include <new> #include <new>
#include <AutoDeleter.h>
#include <Drivers.h> #include <Drivers.h>
#include <KernelExport.h> #include <KernelExport.h>
#include <Select.h> #include <Select.h>
@@ -162,18 +163,19 @@ add_ancillary_data(net_socket *socket, ancillary_data_container* container,
static status_t static status_t
process_ancillary_data(net_socket *socket, ancillary_data_container* container, process_ancillary_data(net_socket *socket, ancillary_data_container* container,
msghdr *_header) msghdr *messageHeader)
{ {
if (container == NULL) uint8 *dataBuffer = (uint8*)messageHeader->msg_control;
return B_OK; int dataBufferLen = messageHeader->msg_controllen;
uint8 *dataBuffer = (uint8*)_header->msg_control; if (container == NULL || dataBuffer == NULL) {
int dataBufferLen = _header->msg_controllen; messageHeader->msg_controllen = 0;
return B_OK;
}
ancillary_data_header header; ancillary_data_header header;
void *data = NULL; void *data = NULL;
while ((data = next_ancillary_data(container, data, &header)) != NULL) { while ((data = next_ancillary_data(container, data, &header)) != NULL) {
if (socket->first_info->process_ancillary_data == NULL) if (socket->first_info->process_ancillary_data == NULL)
return EOPNOTSUPP; return EOPNOTSUPP;
@@ -187,12 +189,45 @@ process_ancillary_data(net_socket *socket, ancillary_data_container* container,
dataBufferLen -= bytesWritten; dataBufferLen -= bytesWritten;
} }
_header->msg_controllen -= dataBufferLen; messageHeader->msg_controllen -= dataBufferLen;
return B_OK; return B_OK;
} }
static ssize_t
socket_receive_no_buffer(net_socket *socket, msghdr *header, void *data,
size_t length, int flags)
{
iovec stackVec = { data, length };
iovec* vecs = header ? header->msg_iov : &stackVec;
int vecCount = header ? header->msg_iovlen : 1;
sockaddr* address = header ? (sockaddr*)header->msg_name : NULL;
socklen_t* addressLen = header ? &header->msg_namelen : NULL;
ancillary_data_container* ancillaryData = NULL;
ssize_t bytesRead = socket->first_info->read_data_no_buffer(
socket->first_protocol, vecs, vecCount, &ancillaryData, address,
addressLen);
if (bytesRead < 0)
return bytesRead;
CObjectDeleter<ancillary_data_container> ancillaryDataDeleter(ancillaryData,
&delete_ancillary_data_container);
// process ancillary data
if (header != NULL) {
status_t status = process_ancillary_data(socket, ancillaryData, header);
if (status != B_OK)
return status;
header->msg_flags = 0;
}
return bytesRead;
}
// #pragma mark - // #pragma mark -
@@ -919,9 +954,12 @@ ssize_t
socket_receive(net_socket *socket, msghdr *header, void *data, size_t length, socket_receive(net_socket *socket, msghdr *header, void *data, size_t length,
int flags) int flags)
{ {
// If the protocol sports read_data_no_buffer() we use it.
if (socket->first_info->read_data_no_buffer != NULL)
return socket_receive_no_buffer(socket, header, data, length, flags);
size_t totalLength = length; size_t totalLength = length;
net_buffer *buffer; net_buffer *buffer;
iovec tmp;
int i; int i;
// the convention to this function is that have header been // the convention to this function is that have header been
@@ -930,13 +968,8 @@ socket_receive(net_socket *socket, msghdr *header, void *data, size_t length,
if (header) { if (header) {
// calculate the length considering all of the extra buffers // calculate the length considering all of the extra buffers
for (i = 1; i < header->msg_iovlen; i++) { for (i = 1; i < header->msg_iovlen; i++)
if (user_memcpy(&tmp, header->msg_iov + i, sizeof(iovec)) < B_OK) totalLength += header->msg_iov[i].iov_len;
return B_BAD_ADDRESS;
if (tmp.iov_len > 0 && tmp.iov_base == NULL)
return B_BAD_ADDRESS;
totalLength += tmp.iov_len;
}
} }
status_t status = socket->first_info->read_data( status_t status = socket->first_info->read_data(
@@ -989,13 +1022,12 @@ socket_receive(net_socket *socket, msghdr *header, void *data, size_t length,
// we only start considering at iovec[1] // we only start considering at iovec[1]
// as { data, length } is iovec[0] // as { data, length } is iovec[0]
for (i = 1; i < header->msg_iovlen && bytesCopied < bytesReceived; i++) { for (i = 1; i < header->msg_iovlen && bytesCopied < bytesReceived; i++) {
if (user_memcpy(&tmp, header->msg_iov + i, sizeof(iovec)) < B_OK) iovec& vec = header->msg_iov[i];
break; size_t toRead = min_c(bytesReceived - bytesCopied, vec.iov_len);
if (gNetBufferModule.read(buffer, bytesCopied, vec.iov_base,
size_t toRead = min_c(bytesReceived - bytesCopied, tmp.iov_len); toRead) < B_OK) {
if (gNetBufferModule.read(buffer, bytesCopied, tmp.iov_base,
toRead) < B_OK)
break; break;
}
bytesCopied += toRead; bytesCopied += toRead;
} }
@@ -1031,24 +1063,25 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length,
if (length > SSIZE_MAX) if (length > SSIZE_MAX)
return B_BAD_VALUE; return B_BAD_VALUE;
// the convention to this function is that have header been ancillary_data_container *ancillaryData = NULL;
// present, { data, length } would have been iovec[0] and is CObjectDeleter<ancillary_data_container> ancillaryDataDeleter(NULL,
// always considered like that &delete_ancillary_data_container);
cmsghdr *ancillaryData = NULL;
size_t ancillaryDataLen = 0;
if (header != NULL) { if (header != NULL) {
address = (const sockaddr *)header->msg_name; address = (const sockaddr *)header->msg_name;
addressLength = header->msg_namelen; addressLength = header->msg_namelen;
ancillaryData = (cmsghdr *)header->msg_control;
ancillaryDataLen = header->msg_controllen;
if (header->msg_iovlen <= 1) // get the ancillary data
header = NULL; if (header->msg_control != NULL) {
else { ancillaryData = create_ancillary_data_container();
bytesLeft += compute_user_iovec_length(header->msg_iov + 1, if (ancillaryData == NULL)
header->msg_iovlen - 1); return B_NO_MEMORY;
ancillaryDataDeleter.SetTo(ancillaryData);
status_t status = add_ancillary_data(socket, ancillaryData,
(cmsghdr *)header->msg_control, header->msg_controllen);
if (status != B_OK)
return status;
} }
} }
@@ -1082,6 +1115,33 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length,
return status; return status;
} }
// If the protocol has a send_data_no_buffer() hook, we use that one.
if (socket->first_info->send_data_no_buffer != NULL) {
iovec stackVec = { (void*)data, length };
iovec* vecs = header ? header->msg_iov : &stackVec;
int vecCount = header ? header->msg_iovlen : 1;
ssize_t written = socket->first_info->send_data_no_buffer(
socket->first_protocol, vecs, vecCount, ancillaryData, address,
addressLength);
if (written > 0)
ancillaryDataDeleter.Detach();
return written;
}
// By convention, if a header is given, the (data, length) equals the first
// iovec. So drop the header, if it is the only iovec. Otherwise compute
// the size of the remaining ones.
if (header != NULL) {
if (header->msg_iovlen <= 1)
header = NULL;
else {
// TODO: The iovecs have already been copied to kernel space. Simplify!
bytesLeft += compute_user_iovec_length(header->msg_iov + 1,
header->msg_iovlen - 1);
}
}
ssize_t bytesSent = 0; ssize_t bytesSent = 0;
size_t vecOffset = 0; size_t vecOffset = 0;
uint32 vecIndex = 0; uint32 vecIndex = 0;
@@ -1134,15 +1194,8 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length,
// attach ancillary data to the first buffer // attach ancillary data to the first buffer
status_t status = B_OK; status_t status = B_OK;
if (ancillaryData != NULL) { if (ancillaryData != NULL) {
ancillary_data_container *container gNetBufferModule.set_ancillary_data(buffer, ancillaryData);
= create_ancillary_data_container(); ancillaryDataDeleter.Detach();
if (container != NULL) {
gNetBufferModule.set_ancillary_data(buffer, container);
status = add_ancillary_data(socket, container, ancillaryData,
ancillaryDataLen);
} else
status = B_NO_MEMORY;
ancillaryData = NULL; ancillaryData = NULL;
} }