From 97cdbb548e22a4e467360b8e7d850f13ab5ff9be Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 12 Apr 2008 09:28:05 +0000 Subject: [PATCH] Added support for sending/receiving ancillary data. The protocol modules have two more optional hooks for attaching supplied ancillary data to a net_buffer and for processing received ancillary data. Not sure, if that is flexible enough for all kinds of ancillary data, but it is for SCM_RIGHTS and also should for SCM_CRED[ENTIAL]S (if we ever decide to implement one of those) -- don't know any other types on other protocol levels. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24941 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/net/net_protocol.h | 6 ++ .../kernel/network/stack/net_socket.cpp | 87 ++++++++++++++++++- 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index 3974a979cd..5781b2d02d 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -68,6 +68,12 @@ struct net_protocol_module_info { status_t (*error)(uint32 code, net_buffer *data); 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); + ssize_t (*process_ancillary_data)(net_protocol *self, + const ancillary_data_header *header, const void *data, + void *buffer, size_t bufferSize); }; #endif // NET_PROTOCOL_H diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index 9cdff52758..1147c209a3 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -133,6 +133,62 @@ err1: } +static status_t +attach_ancillary_data(net_socket *socket, net_buffer *buffer, void *data, + size_t dataLen) +{ + cmsghdr *header = (cmsghdr*)data; + + while (dataLen > 0) { + if (header->cmsg_len < sizeof(cmsghdr) || header->cmsg_len > dataLen) + return B_BAD_VALUE; + + if (socket->first_info->attach_ancillary_data == NULL) + return EOPNOTSUPP; + + status_t status = socket->first_info->attach_ancillary_data( + socket->first_protocol, buffer, header); + if (status != B_OK) + return status; + + dataLen -= _ALIGN(header->cmsg_len); + header = (cmsghdr*)((uint8*)header + _ALIGN(header->cmsg_len)); + } + + return B_OK; +} + + +static status_t +process_ancillary_data(net_socket *socket, net_buffer *buffer, msghdr *_header) +{ + 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) { + + if (socket->first_info->process_ancillary_data == NULL) + return EOPNOTSUPP; + + ssize_t bytesWritten = socket->first_info->process_ancillary_data( + socket->first_protocol, &header, data, dataBuffer, dataBufferLen); + if (bytesWritten < 0) + return bytesWritten; + + dataBuffer += bytesWritten; + dataBufferLen -= bytesWritten; + } + + _header->msg_controllen -= dataBufferLen; + + return B_OK; +} + + // #pragma mark - @@ -891,6 +947,18 @@ socket_receive(net_socket *socket, msghdr *header, void *data, size_t length, if (status < B_OK) return status; + // process ancillary data + if (header != NULL) { + if (buffer != NULL && header->msg_control != NULL) { + status = process_ancillary_data(socket, buffer, header); + if (status != B_OK) { + gNetBufferModule.free(buffer); + return status; + } + } else + header->msg_controllen = 0; + } + // TODO: - returning a NULL buffer when received 0 bytes // may not make much sense as we still need the address // - gNetBufferModule.read() uses memcpy() instead of user_memcpy @@ -969,9 +1037,14 @@ socket_send(net_socket *socket, msghdr *header, const void *data, size_t length, // present, { data, length } would have been iovec[0] and is // always considered like that + cmsghdr *ancillaryData = NULL; + size_t ancillaryDataLen = 0; + 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; @@ -1060,13 +1133,23 @@ 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); + ancillaryData = NULL; + } + size_t bufferSize = buffer->size; buffer->flags = flags; memcpy(buffer->source, &socket->address, socket->address.ss_len); memcpy(buffer->destination, address, addressLength); - status_t status = socket->first_info->send_data(socket->first_protocol, - buffer); + if (status == B_OK) { + status = socket->first_info->send_data(socket->first_protocol, + buffer); + } if (status < B_OK) { size_t sizeAfterSend = buffer->size; gNetBufferModule.free(buffer);