diff --git a/src/pipewire/context.c b/src/pipewire/context.c index 7efcd003d..6adfe9084 100644 --- a/src/pipewire/context.c +++ b/src/pipewire/context.c @@ -553,6 +553,19 @@ static bool global_can_read(struct pw_context *context, struct pw_global *global return true; } +static bool global_is_stale(struct pw_context *context, struct pw_global *global) +{ + struct pw_impl_client *client = context->current_client; + + if (!client) + return false; + + if (client->recv_generation != 0 && global->generation > client->recv_generation) + return true; + + return false; +} + SPA_EXPORT int pw_context_for_each_global(struct pw_context *context, int (*callback) (void *data, struct pw_global *global), @@ -562,7 +575,7 @@ int pw_context_for_each_global(struct pw_context *context, int res; spa_list_for_each_safe(g, t, &context->global_list, link) { - if (!global_can_read(context, g)) + if (!global_can_read(context, g) || global_is_stale(context, g)) continue; if ((res = callback(data, g)) != 0) return res; @@ -581,6 +594,11 @@ struct pw_global *pw_context_find_global(struct pw_context *context, uint32_t id return NULL; } + if (global_is_stale(context, global)) { + errno = global_can_read(context, global) ? ESTALE : ENOENT; + return NULL; + } + if (!global_can_read(context, global)) { errno = EACCES; return NULL; diff --git a/src/pipewire/impl-client.c b/src/pipewire/impl-client.c index d5d865a6b..69f9ac7eb 100644 --- a/src/pipewire/impl-client.c +++ b/src/pipewire/impl-client.c @@ -117,15 +117,16 @@ static int client_error(void *object, uint32_t id, int res, const char *error) struct pw_impl_client *sender = resource->client; struct pw_impl_client *client = data->client; struct error_data d = { id, res, error }; - struct pw_global *global; /* Check the global id provided by sender refers to a registered global * known to the sender. */ - if ((global = pw_context_find_global(resource->context, id)) == NULL) - goto error_no_id; - if (sender->recv_generation != 0 && global->generation > sender->recv_generation) - goto error_stale_id; + if (pw_context_find_global(resource->context, id) == NULL) { + if (errno == ESTALE) + goto error_stale_id; + else + goto error_no_id; + } pw_log_debug("%p: sender %p: error for global %u", client, sender, id); pw_map_for_each(&client->objects, error_resource, &d); @@ -136,8 +137,8 @@ error_no_id: pw_resource_errorf(resource, -ENOENT, "no global %u", id); return -ENOENT; error_stale_id: - pw_log_debug("%p: sender %p: error for stale global %u generation:%"PRIu64" recv-generation:%"PRIu64, - client, sender, id, global->generation, sender->recv_generation); + pw_log_debug("%p: sender %p: error for stale global %u recv-generation:%"PRIu64, + client, sender, id, sender->recv_generation); pw_resource_errorf(resource, -ESTALE, "no global %u any more", id); return -ESTALE; } @@ -804,10 +805,7 @@ int pw_impl_client_check_permissions(struct pw_impl_client *client, uint32_t perms; if ((global = pw_context_find_global(context, global_id)) == NULL) - return -ENOENT; - - if (client->recv_generation != 0 && global->generation > client->recv_generation) - return -ESTALE; + return (errno == ESTALE) ? -ESTALE : -ENOENT; perms = pw_global_get_permissions(global, client); if ((perms & permissions) != permissions) diff --git a/src/pipewire/impl-core.c b/src/pipewire/impl-core.c index f43314c31..cd20051ca 100644 --- a/src/pipewire/impl-core.c +++ b/src/pipewire/impl-core.c @@ -33,17 +33,18 @@ static void * registry_bind(void *object, uint32_t id, struct pw_global *global; uint32_t permissions, new_id = user_data_size; - if ((global = pw_context_find_global(context, id)) == NULL) - goto error_no_id; + if ((global = pw_context_find_global(context, id)) == NULL) { + if (errno == ESTALE) + goto error_stale_id; + else + goto error_no_id; + } permissions = pw_global_get_permissions(global, client); if (!PW_PERM_IS_R(permissions)) goto error_no_id; - if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation) - goto error_stale_id; - if (!spa_streq(global->type, type)) goto error_wrong_interface; @@ -57,8 +58,8 @@ static void * registry_bind(void *object, uint32_t id, error_stale_id: pw_log_debug("registry %p: not binding stale global " - "id %u to %u, generation:%"PRIu64" recv-generation:%"PRIu64, - resource, id, new_id, global->generation, resource->client->recv_generation); + "id %u to %u recv-generation:%"PRIu64, + resource, id, new_id, resource->client->recv_generation); pw_resource_errorf_id(resource, new_id, -ESTALE, "no global %u any more", id); goto error_exit_clean; error_no_id: @@ -88,17 +89,18 @@ static int registry_destroy(void *object, uint32_t id) uint32_t permissions; int res; - if ((global = pw_context_find_global(context, id)) == NULL) - goto error_no_id; + if ((global = pw_context_find_global(context, id)) == NULL) { + if (errno == ESTALE) + goto error_stale_id; + else + goto error_no_id; + } permissions = pw_global_get_permissions(global, client); if (!PW_PERM_IS_R(permissions)) goto error_no_id; - if (resource->client->recv_generation != 0 && global->generation > resource->client->recv_generation) - goto error_stale_id; - if (id == PW_ID_CORE || !PW_PERM_IS_X(permissions)) goto error_not_allowed; @@ -109,8 +111,8 @@ static int registry_destroy(void *object, uint32_t id) error_stale_id: pw_log_debug("registry %p: not destroying stale global " - "id %u, generation:%"PRIu64" recv-generation:%"PRIu64, - resource, id, global->generation, resource->client->recv_generation); + "id %u, recv-generation:%"PRIu64, + resource, id, resource->client->recv_generation); pw_resource_errorf(resource, -ESTALE, "no global %u any more", id); res = -ESTALE; goto error_exit;