global: emit permissions_changed event

Add a permissions_changed event when the permissions change for a
global for a client.
Recheck if a link is still allowed when node permissions changed
and destroy the link if not.
This commit is contained in:
Wim Taymans 2019-05-13 17:04:43 +02:00
parent 83bc033837
commit 98da5a2e9e
4 changed files with 38 additions and 3 deletions

View file

@ -395,6 +395,7 @@ static int do_permissions(void *data, struct pw_global *global)
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
struct permission *p;
size_t len, i;
uint32_t old;
len = pw_array_get_len(&impl->permissions, struct permission);
if (len <= global->id) {
@ -410,12 +411,16 @@ static int do_permissions(void *data, struct pw_global *global)
p = pw_array_get_unchecked(&impl->permissions, global->id, struct permission);
if (p->permissions == -1)
p->permissions = impl->permissions_default;
old = p->permissions = impl->permissions_default;
else if (update->only_new)
return 0;
old = p->permissions;
p->permissions &= update->permissions;
pw_log_debug("client %p: set global %d permissions to %08x", client, global->id, p->permissions);
pw_log_debug("client %p: change global %d permissions %08x -> %08x",
client, global->id, old, p->permissions);
pw_global_events_permissions_changed(global, client, old, p->permissions);
return 0;
}

View file

@ -57,7 +57,7 @@ struct pw_global;
/** Global events, use \ref pw_global_add_listener */
struct pw_global_events {
#define PW_VERSION_GLOBAL_EVENTS 0
#define PW_VERSION_GLOBAL_EVENTS 1
uint32_t version;
/** The global is destroyed */
@ -72,6 +72,12 @@ struct pw_global_events {
uint32_t permissions, /**< permissions for the bind */
uint32_t version, /**< client interface version */
uint32_t id /**< client proxy id */);
/* permissions for the global changed, Since version 1 */
void (*permissions_changed) (void *data,
struct pw_client *client,
uint32_t old_permissions,
uint32_t new_permissions);
};
/** Create a new global object */

View file

@ -51,8 +51,10 @@ struct impl {
struct spa_hook input_port_listener;
struct spa_hook input_node_listener;
struct spa_hook input_global_listener;
struct spa_hook output_port_listener;
struct spa_hook output_node_listener;
struct spa_hook output_global_listener;
};
struct resource_data {
@ -868,6 +870,7 @@ static void input_remove(struct pw_link *this, struct pw_port *port)
pw_log_debug("link %p: remove input port %p", this, port);
spa_hook_remove(&impl->input_port_listener);
spa_hook_remove(&impl->input_node_listener);
spa_hook_remove(&impl->input_global_listener);
pw_loop_invoke(port->node->data_loop,
do_remove_input, 1, NULL, 0, true, this);
@ -897,6 +900,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port)
pw_log_debug("link %p: remove output port %p", this, port);
spa_hook_remove(&impl->output_port_listener);
spa_hook_remove(&impl->output_node_listener);
spa_hook_remove(&impl->output_global_listener);
pw_loop_invoke(port->node->data_loop,
do_remove_output, 1, NULL, 0, true, this);
@ -1105,9 +1109,25 @@ check_permission(struct pw_core *core,
if ((client = input_node->global->owner) != NULL &&
!PW_PERM_IS_R(pw_global_get_permissions(output_node->global, client)))
return -EPERM;
return 0;
}
static void global_permissions_changed(void *data,
struct pw_client *client, uint32_t old, uint32_t new)
{
struct pw_link *this = data;
if (check_permission(this->core, this->output, this->input, this->properties) < 0)
pw_link_destroy(this);
}
static const struct pw_global_events global_node_events = {
PW_VERSION_GLOBAL_EVENTS,
.permissions_changed = global_permissions_changed,
};
SPA_EXPORT
struct pw_link *pw_link_new(struct pw_core *core,
struct pw_port *output,
@ -1166,8 +1186,10 @@ struct pw_link *pw_link_new(struct pw_core *core,
pw_port_add_listener(input, &impl->input_port_listener, &input_port_events, impl);
pw_node_add_listener(input_node, &impl->input_node_listener, &input_node_events, impl);
pw_global_add_listener(input_node->global, &impl->input_global_listener, &global_node_events, impl);
pw_port_add_listener(output, &impl->output_port_listener, &output_port_events, impl);
pw_node_add_listener(output_node, &impl->output_node_listener, &output_node_events, impl);
pw_global_add_listener(output_node->global, &impl->output_global_listener, &global_node_events, impl);
input_node->live = output_node->live;
if (output_node->clock)

View file

@ -124,6 +124,8 @@ struct pw_client {
#define pw_global_events_destroy(g) pw_global_events_emit(g, destroy, 0)
#define pw_global_events_free(g) pw_global_events_emit(g, free, 0)
#define pw_global_events_bind(g,...) pw_global_events_emit(g, bind, 0, __VA_ARGS__)
#define pw_global_events_permissions_changed(g,...) \
pw_global_events_emit(g, permissions_changed, 1, __VA_ARGS__)
struct pw_global {
struct pw_core *core; /**< the core */