From 36708e6ab8fb1d8eedc9bfbc559a6b78036ae9cb Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Tue, 5 Nov 2024 15:23:24 -0500 Subject: [PATCH] network: Let modules process all ancillary data at once, and adjust UNIX. This way, modules can decide to do different things based on having all the ancillary data available. In particular, the UNIX module will now post only one message header for all the FDs, even if they came from multiple sets of ancillary data. This should fix "Message needs unreceived descriptors" from the Chromium IPC code (which is used by Firefox). --- headers/private/net/net_protocol.h | 2 +- headers/private/net/net_stack.h | 2 +- .../kernel/network/protocols/unix/unix.cpp | 65 +++++++++++-------- .../kernel/network/stack/ancillary_data.cpp | 2 +- .../kernel/network/stack/ancillary_data.h | 2 +- .../kernel/network/stack/net_socket.cpp | 23 ++----- 6 files changed, 50 insertions(+), 46 deletions(-) diff --git a/headers/private/net/net_protocol.h b/headers/private/net/net_protocol.h index b01a36b739..8d0a26239d 100644 --- a/headers/private/net/net_protocol.h +++ b/headers/private/net/net_protocol.h @@ -101,7 +101,7 @@ struct net_protocol_module_info { status_t (*add_ancillary_data)(net_protocol* self, ancillary_data_container* container, const cmsghdr* header); ssize_t (*process_ancillary_data)(net_protocol* self, - const ancillary_data_header* header, const void* data, + const ancillary_data_container* container, void* buffer, size_t bufferSize); ssize_t (*process_ancillary_data_no_container)(net_protocol* self, net_buffer* buffer, void* data, size_t bufferSize); diff --git a/headers/private/net/net_stack.h b/headers/private/net/net_stack.h index 1ec5e87f01..7120bd096c 100644 --- a/headers/private/net/net_stack.h +++ b/headers/private/net/net_stack.h @@ -180,7 +180,7 @@ struct net_stack_module_info { void* data, bool destroy); void* (*move_ancillary_data)(ancillary_data_container* from, ancillary_data_container* to); - void* (*next_ancillary_data)(ancillary_data_container* container, + void* (*next_ancillary_data)(const ancillary_data_container* container, void* previousData, ancillary_data_header* _header); }; diff --git a/src/add-ons/kernel/network/protocols/unix/unix.cpp b/src/add-ons/kernel/network/protocols/unix/unix.cpp index a7a1d0907c..8f156d8deb 100644 --- a/src/add-ons/kernel/network/protocols/unix/unix.cpp +++ b/src/add-ons/kernel/network/protocols/unix/unix.cpp @@ -353,52 +353,65 @@ unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container, ssize_t unix_process_ancillary_data(net_protocol *self, - const ancillary_data_header *header, const void *data, void *buffer, + const ancillary_data_container *container, void *buffer, size_t bufferSize) { - TRACE("[%" B_PRId32 "] unix_process_ancillary_data(%p, %p (level: %d, " - "type: %d, len: %lu), %p, %p, %lu)\n", find_thread(NULL), self, header, - header->level, header->type, header->len, data, buffer, bufferSize); + TRACE("[%" B_PRId32 "] unix_process_ancillary_data(%p, %p, %p, %p, %lu)\n", + find_thread(NULL), self, container, buffer, bufferSize); - // we support only SCM_RIGHTS - if (header->level != SOL_SOCKET || header->type != SCM_RIGHTS) - return B_BAD_VALUE; + int totalCount = 0; - int count = header->len / sizeof(file_descriptor*); - file_descriptor** descriptors = (file_descriptor**)data; + ancillary_data_header header; + void* data = NULL; + while ((data = gStackModule->next_ancillary_data(container, data, &header)) != NULL) { + // we support only SCM_RIGHTS + if (header.level != SOL_SOCKET || header.type != SCM_RIGHTS) + return B_BAD_VALUE; + + totalCount += header.len / sizeof(file_descriptor*); + } // check if there's enough space in the buffer - size_t neededBufferSpace = CMSG_SPACE(sizeof(int) * count); + size_t neededBufferSpace = CMSG_SPACE(sizeof(int) * totalCount); if (bufferSize < neededBufferSpace) return B_BAD_VALUE; // init header cmsghdr* messageHeader = (cmsghdr*)buffer; - messageHeader->cmsg_level = header->level; - messageHeader->cmsg_type = header->type; - messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * count); + messageHeader->cmsg_level = SOL_SOCKET; + messageHeader->cmsg_type = SCM_RIGHTS; + messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * totalCount); // create FDs for the current process int* fds = (int*)CMSG_DATA(messageHeader); io_context* ioContext = get_current_io_context(!gStackModule->is_syscall()); status_t error = B_OK; - for (int i = 0; i < count; i++) { - // Get an additional reference which will go to the FD table index. The - // reference and open reference acquired in unix_add_ancillary_data() - // will be released when the container is destroyed. - inc_fd_ref_count(descriptors[i]); - fds[i] = new_fd(ioContext, descriptors[i]); + int i = 0; + data = NULL; + while ((data = gStackModule->next_ancillary_data(container, data, &header)) != NULL) { + int count = header.len / sizeof(file_descriptor*); + file_descriptor** descriptors = (file_descriptor**)data; - if (fds[i] < 0) { - error = fds[i]; - put_fd(descriptors[i]); + for (int k = 0; k < count; k++, i++) { + // Get an additional reference which will go to the FD table index. The + // reference and open reference acquired in unix_add_ancillary_data() + // will be released when the container is destroyed. + inc_fd_ref_count(descriptors[k]); + fds[i] = new_fd(ioContext, descriptors[k]); - // close FD indices - for (int k = i - 1; k >= 0; k--) - close_fd_index(ioContext, fds[k]); - break; + if (fds[i] < 0) { + error = fds[i]; + put_fd(descriptors[k]); + + // close FD indices + for (int j = i - 1; j >= 0; j--) + close_fd_index(ioContext, fds[j]); + break; + } } + if (error != B_OK) + break; } return error == B_OK ? neededBufferSpace : error; diff --git a/src/add-ons/kernel/network/stack/ancillary_data.cpp b/src/add-ons/kernel/network/stack/ancillary_data.cpp index d5baf68375..ba1e276d94 100644 --- a/src/add-ons/kernel/network/stack/ancillary_data.cpp +++ b/src/add-ons/kernel/network/stack/ancillary_data.cpp @@ -183,7 +183,7 @@ move_ancillary_data(ancillary_data_container* from, the last one. */ void* -next_ancillary_data(ancillary_data_container* container, void* previousData, +next_ancillary_data(const ancillary_data_container* container, void* previousData, ancillary_data_header* _header) { ancillary_data *ancillaryData; diff --git a/src/add-ons/kernel/network/stack/ancillary_data.h b/src/add-ons/kernel/network/stack/ancillary_data.h index cd194ccffb..fd012ba983 100644 --- a/src/add-ons/kernel/network/stack/ancillary_data.h +++ b/src/add-ons/kernel/network/stack/ancillary_data.h @@ -22,7 +22,7 @@ status_t remove_ancillary_data(ancillary_data_container* container, void* data, void* move_ancillary_data(ancillary_data_container* from, ancillary_data_container* to); -void* next_ancillary_data(ancillary_data_container* container, +void* next_ancillary_data(const ancillary_data_container* container, void* previousData, ancillary_data_header* _header); diff --git a/src/add-ons/kernel/network/stack/net_socket.cpp b/src/add-ons/kernel/network/stack/net_socket.cpp index f6d588f509..e431c4d6cd 100644 --- a/src/add-ons/kernel/network/stack/net_socket.cpp +++ b/src/add-ons/kernel/network/stack/net_socket.cpp @@ -243,24 +243,15 @@ process_ancillary_data(net_socket* socket, ancillary_data_container* container, return B_OK; } - ancillary_data_header header; - void* data = NULL; + if (socket->first_info->process_ancillary_data == NULL) + return B_NOT_SUPPORTED; - while ((data = next_ancillary_data(container, data, &header)) != NULL) { - if (socket->first_info->process_ancillary_data == NULL) - return B_NOT_SUPPORTED; - - 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; - } - - messageHeader->msg_controllen -= dataBufferLen; + ssize_t bytesWritten = socket->first_info->process_ancillary_data( + socket->first_protocol, container, dataBuffer, dataBufferLen); + if (bytesWritten < 0) + return bytesWritten; + messageHeader->msg_controllen = bytesWritten; return B_OK; }