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
+1 -1
View File
@@ -101,7 +101,7 @@ struct net_protocol_module_info {
status_t (*add_ancillary_data)(net_protocol* self, status_t (*add_ancillary_data)(net_protocol* self,
ancillary_data_container* container, const cmsghdr* header); ancillary_data_container* container, const cmsghdr* header);
ssize_t (*process_ancillary_data)(net_protocol* self, 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); void* buffer, size_t bufferSize);
ssize_t (*process_ancillary_data_no_container)(net_protocol* self, ssize_t (*process_ancillary_data_no_container)(net_protocol* self,
net_buffer* buffer, void* data, size_t bufferSize); net_buffer* buffer, void* data, size_t bufferSize);
+1 -1
View File
@@ -180,7 +180,7 @@ struct net_stack_module_info {
void* data, bool destroy); void* data, bool destroy);
void* (*move_ancillary_data)(ancillary_data_container* from, void* (*move_ancillary_data)(ancillary_data_container* from,
ancillary_data_container* to); 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); void* previousData, ancillary_data_header* _header);
}; };
@@ -353,52 +353,65 @@ unix_add_ancillary_data(net_protocol *self, ancillary_data_container *container,
ssize_t ssize_t
unix_process_ancillary_data(net_protocol *self, 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) size_t bufferSize)
{ {
TRACE("[%" B_PRId32 "] unix_process_ancillary_data(%p, %p (level: %d, " TRACE("[%" B_PRId32 "] unix_process_ancillary_data(%p, %p, %p, %p, %lu)\n",
"type: %d, len: %lu), %p, %p, %lu)\n", find_thread(NULL), self, header, find_thread(NULL), self, container, buffer, bufferSize);
header->level, header->type, header->len, data, buffer, bufferSize);
// we support only SCM_RIGHTS int totalCount = 0;
if (header->level != SOL_SOCKET || header->type != SCM_RIGHTS)
return B_BAD_VALUE;
int count = header->len / sizeof(file_descriptor*); ancillary_data_header header;
file_descriptor** descriptors = (file_descriptor**)data; 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 // 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) if (bufferSize < neededBufferSpace)
return B_BAD_VALUE; return B_BAD_VALUE;
// init header // init header
cmsghdr* messageHeader = (cmsghdr*)buffer; cmsghdr* messageHeader = (cmsghdr*)buffer;
messageHeader->cmsg_level = header->level; messageHeader->cmsg_level = SOL_SOCKET;
messageHeader->cmsg_type = header->type; messageHeader->cmsg_type = SCM_RIGHTS;
messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * count); messageHeader->cmsg_len = CMSG_LEN(sizeof(int) * totalCount);
// create FDs for the current process // create FDs for the current process
int* fds = (int*)CMSG_DATA(messageHeader); int* fds = (int*)CMSG_DATA(messageHeader);
io_context* ioContext = get_current_io_context(!gStackModule->is_syscall()); io_context* ioContext = get_current_io_context(!gStackModule->is_syscall());
status_t error = B_OK; status_t error = B_OK;
for (int i = 0; i < count; i++) { int i = 0;
// Get an additional reference which will go to the FD table index. The data = NULL;
// reference and open reference acquired in unix_add_ancillary_data() while ((data = gStackModule->next_ancillary_data(container, data, &header)) != NULL) {
// will be released when the container is destroyed. int count = header.len / sizeof(file_descriptor*);
inc_fd_ref_count(descriptors[i]); file_descriptor** descriptors = (file_descriptor**)data;
fds[i] = new_fd(ioContext, descriptors[i]);
if (fds[i] < 0) { for (int k = 0; k < count; k++, i++) {
error = fds[i]; // Get an additional reference which will go to the FD table index. The
put_fd(descriptors[i]); // 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 if (fds[i] < 0) {
for (int k = i - 1; k >= 0; k--) error = fds[i];
close_fd_index(ioContext, fds[k]); put_fd(descriptors[k]);
break;
// 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; return error == B_OK ? neededBufferSpace : error;
@@ -183,7 +183,7 @@ move_ancillary_data(ancillary_data_container* from,
the last one. the last one.
*/ */
void* 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_header* _header)
{ {
ancillary_data *ancillaryData; ancillary_data *ancillaryData;
@@ -22,7 +22,7 @@ status_t remove_ancillary_data(ancillary_data_container* container, void* data,
void* move_ancillary_data(ancillary_data_container* from, void* move_ancillary_data(ancillary_data_container* from,
ancillary_data_container* to); 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); void* previousData, ancillary_data_header* _header);
@@ -243,24 +243,15 @@ process_ancillary_data(net_socket* socket, ancillary_data_container* container,
return B_OK; return B_OK;
} }
ancillary_data_header header; if (socket->first_info->process_ancillary_data == NULL)
void* data = NULL; return B_NOT_SUPPORTED;
while ((data = next_ancillary_data(container, data, &header)) != NULL) { ssize_t bytesWritten = socket->first_info->process_ancillary_data(
if (socket->first_info->process_ancillary_data == NULL) socket->first_protocol, container, dataBuffer, dataBufferLen);
return B_NOT_SUPPORTED; if (bytesWritten < 0)
return bytesWritten;
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;
messageHeader->msg_controllen = bytesWritten;
return B_OK; return B_OK;
} }