mirror of
https://review.haiku-os.org/haiku
synced 2024-11-23 07:18:40 +01:00
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:
parent
85a9e4abfb
commit
36708e6ab8
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user