From cdc00dadfc37de5c4c37a45e90ec2e61633d7f60 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 3 May 2008 01:11:21 +0000 Subject: [PATCH] * 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 --- headers/private/net/net_protocol.h | 9 ++ src/add-ons/kernel/network/stack/Jamfile | 2 +- .../kernel/network/stack/net_socket.cpp | 139 ++++++++++++------ 3 files changed, 106 insertions(+), 44 deletions(-) diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index 1ae88fc878..22ebac508e 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -19,6 +19,8 @@ struct ancillary_data_container; struct ancillary_data_header; +struct iovec; + typedef struct net_protocol { struct net_protocol *next; struct net_protocol_module_info *module; @@ -77,6 +79,13 @@ struct net_protocol_module_info { ssize_t (*process_ancillary_data)(net_protocol *self, const ancillary_data_header *header, const void *data, 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 diff --git a/src/add-ons/kernel/network/stack/Jamfile b/src/add-ons/kernel/network/stack/Jamfile index 2846f9c37b..d11bd6480f 100644 --- a/src/add-ons/kernel/network/stack/Jamfile +++ b/src/add-ons/kernel/network/stack/Jamfile @@ -12,7 +12,7 @@ if $(TARGET_PLATFORM) != haiku { UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ; -UsePrivateHeaders net ; +UsePrivateHeaders net shared ; KernelAddon stack : ancillary_data.cpp diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index 83ac2d5153..e103d04a36 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -16,6 +16,7 @@ #include +#include #include #include #include @@ -162,18 +163,19 @@ add_ancillary_data(net_socket *socket, ancillary_data_container* container, static status_t process_ancillary_data(net_socket *socket, ancillary_data_container* container, - msghdr *_header) + msghdr *messageHeader) { - if (container == NULL) - return B_OK; + uint8 *dataBuffer = (uint8*)messageHeader->msg_control; + int dataBufferLen = messageHeader->msg_controllen; - uint8 *dataBuffer = (uint8*)_header->msg_control; - int dataBufferLen = _header->msg_controllen; + if (container == NULL || dataBuffer == NULL) { + messageHeader->msg_controllen = 0; + return B_OK; + } ancillary_data_header header; void *data = NULL; - while ((data = next_ancillary_data(container, data, &header)) != NULL) { if (socket->first_info->process_ancillary_data == NULL) return EOPNOTSUPP; @@ -187,12 +189,45 @@ process_ancillary_data(net_socket *socket, ancillary_data_container* container, dataBufferLen -= bytesWritten; } - _header->msg_controllen -= dataBufferLen; + messageHeader->msg_controllen -= dataBufferLen; 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 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 - @@ -919,9 +954,12 @@ ssize_t socket_receive(net_socket *socket, msghdr *header, void *data, size_t length, 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; net_buffer *buffer; - iovec tmp; int i; // 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) { // calculate the length considering all of the extra buffers - for (i = 1; i < header->msg_iovlen; i++) { - if (user_memcpy(&tmp, header->msg_iov + i, sizeof(iovec)) < B_OK) - return B_BAD_ADDRESS; - if (tmp.iov_len > 0 && tmp.iov_base == NULL) - return B_BAD_ADDRESS; - totalLength += tmp.iov_len; - } + for (i = 1; i < header->msg_iovlen; i++) + totalLength += header->msg_iov[i].iov_len; } 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] // as { data, length } is iovec[0] for (i = 1; i < header->msg_iovlen && bytesCopied < bytesReceived; i++) { - if (user_memcpy(&tmp, header->msg_iov + i, sizeof(iovec)) < B_OK) - break; - - size_t toRead = min_c(bytesReceived - bytesCopied, tmp.iov_len); - if (gNetBufferModule.read(buffer, bytesCopied, tmp.iov_base, - toRead) < B_OK) + iovec& vec = header->msg_iov[i]; + size_t toRead = min_c(bytesReceived - bytesCopied, vec.iov_len); + if (gNetBufferModule.read(buffer, bytesCopied, vec.iov_base, + toRead) < B_OK) { break; + } bytesCopied += toRead; } @@ -1031,24 +1063,25 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length, if (length > SSIZE_MAX) return B_BAD_VALUE; - // the convention to this function is that have header been - // present, { data, length } would have been iovec[0] and is - // always considered like that - - cmsghdr *ancillaryData = NULL; - size_t ancillaryDataLen = 0; + ancillary_data_container *ancillaryData = NULL; + CObjectDeleter ancillaryDataDeleter(NULL, + &delete_ancillary_data_container); if (header != NULL) { address = (const sockaddr *)header->msg_name; addressLength = header->msg_namelen; - ancillaryData = (cmsghdr *)header->msg_control; - ancillaryDataLen = header->msg_controllen; - if (header->msg_iovlen <= 1) - header = NULL; - else { - bytesLeft += compute_user_iovec_length(header->msg_iov + 1, - header->msg_iovlen - 1); + // get the ancillary data + if (header->msg_control != NULL) { + ancillaryData = create_ancillary_data_container(); + if (ancillaryData == NULL) + 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; } + // 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; size_t vecOffset = 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 status_t status = B_OK; if (ancillaryData != NULL) { - 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; - + gNetBufferModule.set_ancillary_data(buffer, ancillaryData); + ancillaryDataDeleter.Detach(); ancillaryData = NULL; }