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).
This commit is contained in:
Augustin Cavalier 2024-11-05 15:23:24 -05:00
parent 85a9e4abfb
commit 36708e6ab8
6 changed files with 50 additions and 46 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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