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
This commit is contained in:
Ingo Weinhold 2008-04-12 09:28:05 +00:00
parent 62d7da1f45
commit 97cdbb548e
2 changed files with 91 additions and 2 deletions

View File

@ -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

View File

@ -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);