* 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:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user