summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/examples/export-sink.c21
-rw-r--r--src/examples/media-session.c7
-rw-r--r--src/modules/module-access.c8
-rw-r--r--src/modules/module-protocol-native/protocol-native.c115
-rw-r--r--src/pipewire/client.c215
-rw-r--r--src/pipewire/client.h6
-rw-r--r--src/pipewire/core.c15
-rw-r--r--src/pipewire/core.h10
-rw-r--r--src/pipewire/global.c68
-rw-r--r--src/pipewire/global.h9
-rw-r--r--src/pipewire/interfaces.h49
-rw-r--r--src/pipewire/permission.h60
-rw-r--r--src/tools/pipewire-cli.c17
13 files changed, 281 insertions, 319 deletions
diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c
index ab0cbd1b..9b1a3552 100644
--- a/src/examples/export-sink.c
+++ b/src/examples/export-sink.c
@@ -509,21 +509,18 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo
case PW_REMOTE_STATE_CONNECTED:
{
- struct spa_dict_item items[5];
- int i = 0;
-
- /* set specific permissions on all existing objects without permissions */
- items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_EXISTING, "r--");
- /* set default permission for new objects and objects without
- * specific permissions */
- items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_DEFAULT, "---");
+ struct pw_permission permissions[2];
+
/* an example, set specific permissions on one object, this is the
- * core object, we already have a binding to it that is not affected
- * by the removal of X permissions, only future bindings. */
- items[i++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, "0:rw-");
+ * core object. */
+ permissions[0].id = 0;
+ permissions[0].permissions = PW_PERM_R | PW_PERM_X;
+ /* remove WX from all other objects */
+ permissions[1].id = SPA_ID_INVALID;
+ permissions[1].permissions = PW_PERM_R;
pw_core_proxy_permissions(pw_remote_get_core_proxy(data->remote),
- &SPA_DICT_INIT(items, i));
+ 2, permissions);
make_node(data);
break;
diff --git a/src/examples/media-session.c b/src/examples/media-session.c
index d3709993..c313d143 100644
--- a/src/examples/media-session.c
+++ b/src/examples/media-session.c
@@ -700,7 +700,7 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id,
{
struct pw_proxy *p;
struct client *client;
- struct spa_dict_item items[2];
+ struct pw_permission perms[2];
const char *str;
p = pw_registry_proxy_bind(impl->registry_proxy,
@@ -727,10 +727,9 @@ handle_client(struct impl *impl, uint32_t id, uint32_t parent_id,
return 0;
if (strcmp(str, "restricted") == 0) {
- items[0].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT;
- items[0].value = "rwx";
+ perms[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
pw_client_proxy_update_permissions((struct pw_client_proxy*)p,
- &SPA_DICT_INIT(items, 1));
+ 1, perms);
}
return 0;
}
diff --git a/src/modules/module-access.c b/src/modules/module-access.c
index 08573742..2adfdd7d 100644
--- a/src/modules/module-access.c
+++ b/src/modules/module-access.c
@@ -110,6 +110,7 @@ core_check_access(void *data, struct pw_client *client)
{
struct impl *impl = data;
const struct ucred *ucred;
+ struct pw_permission permissions[1];
struct spa_dict_item items[2];
const char *str;
int res;
@@ -128,7 +129,8 @@ core_check_access(void *data, struct pw_client *client)
if (res == 0)
goto granted;
if (res > 0)
- res = EACCES;
+ res = -EACCES;
+ items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted");
goto blacklisted;
}
@@ -162,7 +164,8 @@ core_check_access(void *data, struct pw_client *client)
granted:
pw_log_debug("module %p: client %p access granted", impl, client);
- pw_client_set_permissions(client, PW_PERM_RWX);
+ permissions[0] = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
+ pw_client_update_permissions(client, 1, permissions);
return;
wait_permissions:
@@ -172,7 +175,6 @@ core_check_access(void *data, struct pw_client *client)
return;
blacklisted:
- items[0] = SPA_DICT_ITEM_INIT("pipewire.access", "blacklisted");
pw_resource_error(pw_client_get_core_resource(client), 0, res, "blacklisted");
pw_client_update_properties(client, &SPA_DICT_INIT(items, 1));
return;
diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c
index 6be0b121..7c7c7dff 100644
--- a/src/modules/module-protocol-native/protocol-native.c
+++ b/src/modules/module-protocol-native/protocol-native.c
@@ -64,22 +64,23 @@ static void core_marshal_client_update(void *object, const struct spa_dict *prop
pw_protocol_native_end_proxy(proxy, b);
}
-static void core_marshal_permissions(void *object, const struct spa_dict *props)
+static void core_marshal_permissions(void *object, uint32_t n_permissions,
+ const struct pw_permission *permissions)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
- int i, n_items;
+ int i;
b = pw_protocol_native_begin_proxy(proxy, PW_CORE_PROXY_METHOD_PERMISSIONS);
- n_items = props ? props->n_items : 0;
-
- spa_pod_builder_add(b, "[ i", n_items, NULL);
+ spa_pod_builder_add(b, "[",
+ "i", n_permissions,
+ NULL);
- for (i = 0; i < n_items; i++) {
+ for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
- "s", props->items[i].key,
- "s", props->items[i].value, NULL);
+ "i", permissions[i].id,
+ "i", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@@ -340,23 +341,25 @@ static int core_demarshal_client_update(void *object, void *data, size_t size)
static int core_demarshal_permissions(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
- struct spa_dict props;
struct spa_pod_parser prs;
- uint32_t i;
+ struct pw_permission *permissions;
+ uint32_t i, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
- if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
+ if (spa_pod_parser_get(&prs, "[",
+ "i", &n_permissions, NULL) < 0)
return -EINVAL;
- props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
- for (i = 0; i < props.n_items; i++) {
+ permissions = alloca(n_permissions * sizeof(struct pw_permission));
+ for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
- "s", &props.items[i].key,
- "s", &props.items[i].value,
+ "i", &permissions[i].id,
+ "i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
- pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0, &props);
+ pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0,
+ n_permissions, permissions);
return 0;
}
@@ -1017,24 +1020,23 @@ static int client_demarshal_info(void *object, void *data, size_t size)
return 0;
}
-static void client_marshal_permissions(void *object, const struct spa_dict *dict)
+static void client_marshal_permissions(void *object, uint32_t index, uint32_t n_permissions,
+ struct pw_permission *permissions)
{
struct pw_resource *resource = object;
struct spa_pod_builder *b;
- uint32_t i, n_items;
+ uint32_t i;
b = pw_protocol_native_begin_resource(resource, PW_CLIENT_PROXY_EVENT_PERMISSIONS);
- n_items = dict ? dict->n_items : 0;
-
spa_pod_builder_add(b,
- "[",
- "i", n_items, NULL);
+ "[ i", index,
+ "i", n_permissions, NULL);
- for (i = 0; i < n_items; i++) {
+ for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
- "s", dict->items[i].key,
- "s", dict->items[i].value, NULL);
+ "s", permissions[i].id,
+ "s", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@@ -1044,23 +1046,24 @@ static void client_marshal_permissions(void *object, const struct spa_dict *dict
static int client_demarshal_permissions(void *object, void *data, size_t size)
{
struct pw_proxy *proxy = object;
- struct spa_dict props;
+ struct pw_permission *permissions;
struct spa_pod_parser prs;
- uint32_t i;
+ uint32_t i, index, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
- if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
+ if (spa_pod_parser_get(&prs, "[ i", &index,
+ "i", &n_permissions, NULL) < 0)
return -EINVAL;
- props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
- for (i = 0; i < props.n_items; i++) {
+ permissions = alloca(n_permissions * sizeof(struct pw_permission));
+ for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
- "s", &props.items[i].key,
- "s", &props.items[i].value,
+ "i", &permissions[i].id,
+ "i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
- pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, &props);
+ pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, index, n_permissions, permissions);
return 0;
}
@@ -1095,14 +1098,16 @@ static int client_demarshal_error(void *object, void *data, size_t size)
return 0;
}
-static void client_marshal_get_permissions(void *object)
+static void client_marshal_get_permissions(void *object, uint32_t index, uint32_t num)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_GET_PERMISSIONS);
- spa_pod_builder_add_struct(b, "P", NULL);
+ spa_pod_builder_add_struct(b,
+ "i", index,
+ "i", num, NULL);
pw_protocol_native_end_proxy(proxy, b);
}
@@ -1111,32 +1116,33 @@ static int client_demarshal_get_permissions(void *object, void *data, size_t siz
{
struct pw_resource *resource = object;
struct spa_pod_parser prs;
- void *ptr;
+ uint32_t index, num;
spa_pod_parser_init(&prs, data, size, 0);
- if (spa_pod_parser_get(&prs, "[P]", &ptr, NULL) < 0)
+ if (spa_pod_parser_get(&prs,
+ "[i", &index,
+ "i", &num, NULL) < 0)
return -EINVAL;
- pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0);
+ pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0, index, num);
return 0;
}
-static void client_marshal_update_permissions(void *object, const struct spa_dict *props)
+static void client_marshal_update_permissions(void *object, uint32_t n_permissions,
+ const struct pw_permission *permissions)
{
struct pw_proxy *proxy = object;
struct spa_pod_builder *b;
- int i, n_items;
+ int i;
b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_UPDATE_PERMISSIONS);
- n_items = props ? props->n_items : 0;
-
- spa_pod_builder_add(b, "[ i", n_items, NULL);
+ spa_pod_builder_add(b, "[ i", n_permissions, NULL);
- for (i = 0; i < n_items; i++) {
+ for (i = 0; i < n_permissions; i++) {
spa_pod_builder_add(b,
- "s", props->items[i].key,
- "s", props->items[i].value, NULL);
+ "i", permissions[i].id,
+ "i", permissions[i].permissions, NULL);
}
spa_pod_builder_add(b, "]", NULL);
@@ -1146,23 +1152,24 @@ static void client_marshal_update_permissions(void *object, const struct spa_dic
static int client_demarshal_update_permissions(void *object, void *data, size_t size)
{
struct pw_resource *resource = object;
- struct spa_dict props;
+ struct pw_permission *permissions;
struct spa_pod_parser prs;
- uint32_t i;
+ uint32_t i, n_permissions;
spa_pod_parser_init(&prs, data, size, 0);
- if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
+ if (spa_pod_parser_get(&prs, "[ i", &n_permissions, NULL) < 0)
return -EINVAL;
- props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
- for (i = 0; i < props.n_items; i++) {
+ permissions = alloca(n_permissions * sizeof(struct pw_permission));
+ for (i = 0; i < n_permissions; i++) {
if (spa_pod_parser_get(&prs,
- "s", &props.items[i].key,
- "s", &props.items[i].value,
+ "i", &permissions[i].id,
+ "i", &permissions[i].permissions,
NULL) < 0)
return -EINVAL;
}
- pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0, &props);
+ pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0,
+ n_permissions, permissions);
return 0;
}
diff --git a/src/pipewire/client.c b/src/pipewire/client.c
index ffde610b..e1bc112a 100644
--- a/src/pipewire/client.c
+++ b/src/pipewire/client.c
@@ -27,11 +27,6 @@
#include "pipewire/private.h"
#include "pipewire/resource.h"
-struct permission {
- uint32_t id;
- uint32_t permissions;
-};
-
/** \cond */
struct impl {
struct pw_client this;
@@ -46,40 +41,40 @@ struct resource_data {
};
/** find a specific permission for a global or NULL when there is none */
-static struct permission *
+static struct pw_permission *
find_permission(struct pw_client *client, uint32_t id)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- struct permission *p;
+ struct pw_permission *p;
- if (!pw_array_check_index(&impl->permissions, id, struct permission))
+ if (!pw_array_check_index(&impl->permissions, id, struct pw_permission))
return NULL;
- p = pw_array_get_unchecked(&impl->permissions, id, struct permission);
+ p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission);
if (p->permissions == -1)
return NULL;
else
return p;
}
-static struct permission *ensure_permissions(struct pw_client *client, uint32_t id)
+static struct pw_permission *ensure_permissions(struct pw_client *client, uint32_t id)
{
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- struct permission *p;
+ struct pw_permission *p;
size_t len, i;
- len = pw_array_get_len(&impl->permissions, struct permission);
+ len = pw_array_get_len(&impl->permissions, struct pw_permission);
if (len <= id) {
size_t diff = id - len + 1;
- p = pw_array_add(&impl->permissions, diff * sizeof(struct permission));
+ p = pw_array_add(&impl->permissions, diff * sizeof(struct pw_permission));
if (p == NULL)
return NULL;
for (i = 0; i < diff; i++)
p[i].permissions = -1;
}
- p = pw_array_get_unchecked(&impl->permissions, id, struct permission);
+ p = pw_array_get_unchecked(&impl->permissions, id, struct pw_permission);
return p;
}
@@ -90,7 +85,7 @@ client_permission_func(struct pw_global *global,
struct pw_client *client, void *data)
{
struct impl *impl = data;
- struct permission *p;
+ struct pw_permission *p;
p = find_permission(client, global->id);
if (p == NULL)
@@ -99,26 +94,6 @@ client_permission_func(struct pw_global *global,
return p->permissions;
}
-static uint32_t parse_mask(const char *str)
-{
- uint32_t mask = 0;
-
- while (*str != '\0') {
- switch (*str++) {
- case 'r':
- mask |= PW_PERM_R;
- break;
- case 'w':
- mask |= PW_PERM_W;
- break;
- case 'x':
- mask |= PW_PERM_X;
- break;
- }
- }
- return mask;
-}
-
static void client_error(void *object, uint32_t id, int res, const char *error)
{
struct pw_resource *resource = object;
@@ -127,65 +102,21 @@ static void client_error(void *object, uint32_t id, int res, const char *error)
pw_resource_error(client->core_resource, id, res, error);
}
-static void client_get_permissions(void *object)
+static void client_get_permissions(void *object, uint32_t index, uint32_t num)
{
struct pw_resource *resource = object;
struct resource_data *data = pw_resource_get_user_data(resource);
struct pw_client *client = data->client;
+ pw_log_debug("client %p", client);
}
-static void client_update_permissions(void *object, const struct spa_dict *props)
+static void client_update_permissions(void *object,
+ uint32_t n_permissions, const struct pw_permission *permissions)
{
struct pw_resource *resource = object;
struct resource_data *data = pw_resource_get_user_data(resource);
struct pw_client *client = data->client;
- struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- const char *str;
- int i, len;
-
- for (i = 0; i < props->n_items; i++) {
- str = props->items[i].value;
-
- pw_log_debug("client %p: %s %s", client, props->items[i].key, str);
-
- if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) {
- impl->permissions_default = parse_mask(str);
- pw_log_debug("client %p: set default permissions to %08x",
- client, impl->permissions_default);
- }
- else if (strcmp(props->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) {
- struct pw_global *global;
- uint32_t global_id, old_perm, new_perm;
- struct permission *p;
-
- /* permissions.update=<global-id>:[r][w][x] */
- len = strcspn(str, ":");
- if (len == 0)
- continue;
-
- global_id = atoi(str);
- global = pw_core_find_global(client->core, global_id);
- if (global == NULL) {
- pw_log_warn("client %p: invalid global %d", client, global_id);
- continue;
- }
-
- p = ensure_permissions(client, global_id);
- old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions;
- new_perm = parse_mask(str + len);
-
- pw_log_debug("client %p: %08x %08x", client, old_perm, new_perm);
-
- p->permissions = new_perm;
-
- if (PW_PERM_IS_R(old_perm) && !PW_PERM_IS_R(new_perm)) {
- pw_global_revoke(global, client);
- }
- else if (!PW_PERM_IS_R(old_perm) && PW_PERM_IS_R(new_perm)) {
- pw_global_grant(global, client);
- }
- }
- }
+ pw_client_update_permissions(client, n_permissions, permissions);
pw_client_set_busy(client, false);
}
@@ -246,7 +177,7 @@ core_global_removed(void *data, struct pw_global *global)
{
struct impl *impl = data;
struct pw_client *client = &impl->this;
- struct permission *p;
+ struct pw_permission *p;
p = find_permission(client, global->id);
pw_log_debug("client %p: global %d removed, %p", client, global->id, p);
@@ -492,91 +423,61 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict
return changed;
}
-struct permissions_update {
- struct pw_client *client;
- uint32_t permissions;
- bool only_new;
-};
-
-static int do_permissions(void *data, struct pw_global *global)
+int pw_client_update_permissions(struct pw_client *client,
+ uint32_t n_permissions, const struct pw_permission *permissions)
{
- struct permissions_update *update = data;
- struct pw_client *client = update->client;
struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- struct permission *p;
-
- p = ensure_permissions(client, global->id);
- if (p == NULL)
- return -ENOMEM;
- if (p->permissions == -1)
- p->permissions = impl->permissions_default;
- else if (update->only_new)
- return 0;
+ struct pw_core *core = client->core;
+ int i;
- p->permissions &= update->permissions;
- pw_log_debug("client %p: set global %d permissions to %08x", client, global->id, p->permissions);
+ for (i = 0; i < n_permissions; i++) {
+ struct pw_permission *p;
+ uint32_t old_perm, new_perm;
+ struct pw_global *global;
- return 0;
-}
+ if (permissions[i].id == SPA_ID_INVALID) {
+ old_perm = impl->permissions_default;
+ new_perm = permissions[i].permissions;
-int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict)
-{
- struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- int i;
- const char *str;
- size_t len;
- struct permissions_update update = { client, 0 };
- uint32_t permissions_existing, permissions_default;
+ if (core->current_client == client)
+ new_perm &= old_perm;
- permissions_default = impl->permissions_default;
- permissions_existing = -1;
+ pw_log_debug("client %p: set default permissions %08x -> %08x",
+ client, old_perm, new_perm);
- for (i = 0; i < dict->n_items; i++) {
- str = dict->items[i].value;
+ spa_list_for_each(global, &core->global_list, link) {
+ p = find_permission(client, global->id);
+ if (p != NULL)
+ continue;
- if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_DEFAULT) == 0) {
- permissions_default &= parse_mask(str);
- pw_log_debug("client %p: set default permissions to %08x",
- client, permissions_default);
+ pw_global_update_permissions(global, client, old_perm, new_perm);
+ }
+ impl->permissions_default = new_perm;
}
- else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_GLOBAL) == 0) {
+ else {
struct pw_global *global;
- uint32_t global_id;
- /* permissions.update=<global-id>:[r][w][x] */
- len = strcspn(str, ":");
- if (len == 0)
- continue;
-
- global_id = atoi(str);
- global = pw_core_find_global(client->core, global_id);
+ global = pw_core_find_global(client->core, permissions[i].id);
if (global == NULL) {
- pw_log_warn("client %p: invalid global %d", client, global_id);
+ pw_log_warn("client %p: invalid global %d", client, permissions[i].id);
continue;
}
+ p = ensure_permissions(client, global->id);
+ old_perm = p->permissions == -1 ? impl->permissions_default : p->permissions;
+ new_perm = permissions[i].permissions;
- /* apply the specific updates in order. This is ok for now, we could add
- * a field to the permission struct later to accumulate the changes
- * and apply them out of this loop */
- update.permissions = parse_mask(str + len);
- update.only_new = false;
- do_permissions(&update, global);
- }
- else if (strcmp(dict->items[i].key, PW_CORE_PROXY_PERMISSIONS_EXISTING) == 0) {
- permissions_existing = parse_mask(str);
- pw_log_debug("client %p: set existing permissions to %08x",
- client, permissions_existing);
+ if (core->current_client == client)
+ new_perm &= old_perm;
+
+ pw_log_debug("client %p: set global %d permissions %08x -> %08x",
+ client, global->id, old_perm, new_perm);
+
+ pw_global_update_permissions(global, client, old_perm, new_perm);
+ p->permissions = new_perm;
}
}
- /* apply default and existing permissions after specific ones to make the
- * permission update look like an atomic unordered set of changes. */
- if (permissions_existing != -1) {
- update.permissions = permissions_existing;
- update.only_new = true;
- pw_core_for_each_global(client->core, do_permissions, &update);
- }
- impl->permissions_default = permissions_default;
-
+ if (n_permissions > 0)
+ pw_client_set_busy(client, false);
return 0;
}
@@ -588,11 +489,3 @@ void pw_client_set_busy(struct pw_client *client, bool busy)
pw_client_events_busy_changed(client, busy);
}
}
-
-void pw_client_set_permissions(struct pw_client *client, uint32_t permissions)
-{
- struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
- pw_log_debug("client %p: permissions %08x", client, permissions);
- impl->permissions_default = permissions;
- pw_client_set_busy(client, false);
-}
diff --git a/src/pipewire/client.h b/src/pipewire/client.h
index 64eba357..4a092fe0 100644
--- a/src/pipewire/client.h
+++ b/src/pipewire/client.h
@@ -49,6 +49,7 @@ struct pw_client;
#include <pipewire/introspect.h>
#include <pipewire/properties.h>
#include <pipewire/resource.h>
+#include <pipewire/permission.h>
#define PW_TYPE__Client PW_TYPE_OBJECT_BASE "Client"
#define PW_TYPE_CLIENT_BASE PW_TYPE__Client ":"
@@ -146,7 +147,8 @@ const struct pw_client_info *pw_client_get_info(struct pw_client *client);
int pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict);
/** Update the client permissions */
-int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict);
+int pw_client_update_permissions(struct pw_client *client, uint32_t n_permissions,
+ const struct pw_permission *permissions);
/** Get the client properties */
const struct pw_properties *pw_client_get_properties(struct pw_client *client);
@@ -177,8 +179,6 @@ void pw_client_add_listener(struct pw_client *client,
* started and no further processing is allowed to happen for the client */
void pw_client_set_busy(struct pw_client *client, bool busy);
-void pw_client_set_permissions(struct pw_client *client, uint32_t permissions);
-
#ifdef __cplusplus
}
#endif
diff --git a/src/pipewire/core.c b/src/pipewire/core.c
index 678b7a60..5a77f744 100644
--- a/src/pipewire/core.c
+++ b/src/pipewire/core.c
@@ -64,11 +64,11 @@ static void registry_bind(void *object, uint32_t id,
if (!PW_PERM_IS_R(permissions))
goto no_id;
- if (type != global->type)
+ if (global->type != type)
goto wrong_interface;
- pw_log_debug("global %p: bind global id %d, iface %s to %d", global, id,
- spa_debug_type_find_name(pw_type_info(), type), new_id);
+ pw_log_debug("global %p: bind global id %d, iface %s/%d to %d", global, id,
+ spa_debug_type_find_name(pw_type_info(), type), version, new_id);
if (pw_global_bind(global, client, permissions, version, new_id) < 0)
goto exit;
@@ -77,9 +77,13 @@ static void registry_bind(void *object, uint32_t id,
no_id:
pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id);
+ pw_core_resource_error(client->core_resource, id,
+ -ENOENT, "no such global %u", id);
goto exit;
wrong_interface:
pw_log_debug("registry %p: global with id %u has no interface %u", resource, id, type);
+ pw_core_resource_error(client->core_resource, id,
+ -ENOENT, "no such interface %u", type);
goto exit;
exit:
/* unmark the new_id the map, the client does not yet know about the failed
@@ -151,10 +155,11 @@ static void core_client_update(void *object, const struct spa_dict *props)
pw_client_update_properties(resource->client, props);
}
-static void core_permissions(void *object, const struct spa_dict *props)
+static void core_permissions(void *object, uint32_t n_permissions,
+ const struct pw_permission *permissions)
{
struct pw_resource *resource = object;
- pw_client_update_permissions(resource->client, props);
+ pw_client_update_permissions(resource->client, n_permissions, permissions);
}
static void core_sync(void *object, uint32_t seq)
diff --git a/src/pipewire/core.h b/src/pipewire/core.h
index 75c5e1c5..71073bd2 100644
--- a/src/pipewire/core.h
+++ b/src/pipewire/core.h
@@ -73,16 +73,6 @@ struct pw_core;
* resources of a PipeWire instance.
*/
-#define PW_PERM_R 0400 /**< object can be seen and events can be received */
-#define PW_PERM_W 0200 /**< methods can be called that modify the object */
-#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
- * present in order to call methods that modify the object. */
-#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
-
-#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
-#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
-#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
-
/** core events emited by the core object added with \ref pw_core_add_listener */
struct pw_core_events {
#define PW_VERSION_CORE_EVENTS 0
diff --git a/src/pipewire/global.c b/src/pipewire/global.c
index 0110933e..79c965d8 100644
--- a/src/pipewire/global.c
+++ b/src/pipewire/global.c
@@ -147,17 +147,19 @@ static int global_unregister(struct pw_global *global)
{
struct impl *impl = SPA_CONTAINER_OF(global, struct impl, this);
struct pw_core *core = global->core;
- struct pw_resource *registry;
+ struct pw_resource *resource;
if (!impl->registered)
return 0;
- spa_list_for_each(registry, &core->registry_resource_list, link) {
- uint32_t permissions = pw_global_get_permissions(global, registry->client);
- pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions);
+ spa_list_for_each(resource, &core->registry_resource_list, link) {
+ uint32_t permissions = pw_global_get_permissions(global, resource->client);
+ pw_log_debug("registry %p: global %d %08x", resource, global->id, permissions);
if (PW_PERM_IS_R(permissions))
- pw_registry_resource_global_remove(registry, global->id);
+ pw_registry_resource_global_remove(resource, global->id);
}
+ spa_list_consume(resource, &global->resource_list, link)
+ pw_resource_destroy(resource);
spa_list_remove(&global->link);
pw_core_events_global_removed(core, global);
@@ -220,17 +222,17 @@ void pw_global_add_listener(struct pw_global *global,
* \param global the global to bind to
* \param client the client that binds
* \param version the version
- * \param id the id
+ * \param id the id of the resource
*
* Let \a client bind to \a global with the given version and id.
* After binding, the client and the global object will be able to
- * exchange messages.
+ * exchange messages on the proxy/resource with \a id.
*
* \memberof pw_global
*/
int
pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t permissions,
- uint32_t version, uint32_t id)
+ uint32_t version, uint32_t id)
{
int res;
@@ -241,55 +243,47 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm
return 0;
- wrong_version:
+ wrong_version:
res = -EINVAL;
pw_core_resource_error(client->core_resource, id,
- res, "id %d: interface version %d < %d",
- id, global->version, version);
+ res, "id %d: interface version %d < %d",
+ id, global->version, version);
return res;
}
-int pw_global_grant(struct pw_global *global, struct pw_client *client)
+int pw_global_update_permissions(struct pw_global *global, struct pw_client *client,
+ uint32_t old_permissions, uint32_t new_permissions)
{
- struct pw_resource *registry;
struct pw_core *core = global->core;
+ struct pw_resource *resource, *t;
- spa_list_for_each(registry, &core->registry_resource_list, link) {
- uint32_t permissions;
-
- if (registry->client != client)
+ spa_list_for_each(resource, &core->registry_resource_list, link) {
+ if (resource->client != client)
continue;
- permissions = pw_global_get_permissions(global, client);
-
- pw_log_debug("registry %p: global %d %08x", registry, global->id, permissions);
- if (PW_PERM_IS_R(permissions))
- pw_registry_resource_global(registry,
+ if (PW_PERM_IS_R(old_permissions) && !PW_PERM_IS_R(new_permissions)) {
+ pw_registry_resource_global_remove(resource, global->id);
+ }
+ else if (!PW_PERM_IS_R(old_permissions) && PW_PERM_IS_R(new_permissions)) {
+ pw_registry_resource_global(resource,
global->id,
global->parent->id,
- permissions,
+ new_permissions,
global->type,
global->version,
global->properties ?
&global->properties->dict : NULL);
- }
- return 0;
-}
-
-int pw_global_revoke(struct pw_global *global, struct pw_client *client)
-{
- struct pw_resource *registry, *resource, *t;
- struct pw_core *core = global->core;
-
- spa_list_for_each(registry, &core->registry_resource_list, link) {
- if (registry->client != client)
- continue;
- pw_registry_resource_global_remove(registry, global->id);
+ }
}
spa_list_for_each_safe(resource, t, &global->resource_list, link) {
if (resource->client != client)
continue;
- pw_resource_destroy(resource);
+
+ /* don't ever destroy the core resource */
+ if (!PW_PERM_IS_R(new_permissions) && global->id != 0)
+ pw_resource_destroy(resource);
+ else
+ resource->permissions = new_permissions;
}
return 0;
}
diff --git a/src/pipewire/global.h b/src/pipewire/global.h
index dcd83127..6eee3670 100644
--- a/src/pipewire/global.h
+++ b/src/pipewire/global.h
@@ -128,13 +128,8 @@ int pw_global_bind(struct pw_global *global,
uint32_t version,
uint32_t id);
-/** Revoke access to global for client, the global will be removed from
- * the client registry and all the bound resources for the client will be
- * destroyed */
-int pw_global_revoke(struct pw_global *global, struct pw_client *client);
-/** Grant access to a global for client. The client registry will be
- * notified of a new global */
-int pw_global_grant(struct pw_global *global, struct pw_client *client);
+int pw_global_update_permissions(struct pw_global *global, struct pw_client *client,
+ uint32_t old_permissions, uint32_t new_permissions);
/** Destroy a global */
void pw_global_destroy(struct pw_global *global);
diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h
index a2553614..c846909c 100644
--- a/src/pipewire/interfaces.h
+++ b/src/pipewire/interfaces.h
@@ -30,6 +30,7 @@ extern "C" {
#include <pipewire/introspect.h>
#include <pipewire/proxy.h>
+#include <pipewire/permission.h>
struct pw_core_proxy;
struct pw_registry_proxy;
@@ -143,18 +144,21 @@ struct pw_core_proxy_methods {
*/
void (*client_update) (void *object, const struct spa_dict *props);
/**
- * Manage the permissions of the global objects
+ * Manage the permissions of the global objects for this
+ * client
*
* Update the permissions of the global objects using the
- * dictionary with properties.
+ * provided array with permissions
*
* Globals can use the default permissions or can have specific
* permissions assigned to them.
*
- * \param id the global id to change
- * \param props dictionary with permission properties
+ * \param n_permissions number of permissions
+ * \param permissions array of permissions
*/
- void (*permissions) (void *object, const struct spa_dict *props);
+ void (*permissions) (void *object,
+ uint32_t n_permissions,
+ const struct pw_permission *permissions);
/**
* Create a new object on the PipeWire server from a factory.
* Use a \a factory_name of "client-node" to create a
@@ -209,9 +213,9 @@ pw_core_proxy_client_update(struct pw_core_proxy *core, const struct spa_dict *p
}
static inline void
-pw_core_proxy_permissions(struct pw_core_proxy *core, const struct spa_dict *props)
+pw_core_proxy_permissions(struct pw_core_proxy *core, uint32_t n_permissions, struct pw_permission *permissions)
{
- pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, props);
+ pw_proxy_do((struct pw_proxy*)core, struct pw_core_proxy_methods, permissions, n_permissions, permissions);
}
static inline void *
@@ -696,9 +700,15 @@ struct pw_client_proxy_events {
*
* Event emited as a result of the get_permissions method.
*
- * \param param the parameter
+ * \param default_permissions the default permissions
+ * \param index the index of the first permission entry
+ * \param n_permissions the number of permissions
+ * \param permissions the permissions
*/
- void (*permissions) (void *object, const struct spa_dict *dict);
+ void (*permissions) (void *object,
+ uint32_t index,
+ uint32_t n_permissions,
+ struct pw_permission *permissions);
};
/** Client */
@@ -736,15 +746,20 @@ struct pw_client_proxy_methods {
* Get client permissions
*
* A permissions event will be emited with the permissions.
+ *
+ * \param index the first index to query, 0 for first
+ * \param num the maximum number of items to get
*/
- void (*get_permissions) (void *object);
+ void (*get_permissions) (void *object, uint32_t index, uint32_t num);
/**
* Update client permissions
*
- * \param dict list of permissions to update
+ * \param n_permissions number of permissions
+ * \param permissions array of new permissions
*/
- void (*update_permissions) (void *object, const struct spa_dict *dict);
+ void (*update_permissions) (void *object, uint32_t n_permissions,
+ const struct pw_permission *permissions);
};
/** Client permissions */
@@ -755,15 +770,17 @@ pw_client_proxy_error(struct pw_client_proxy *client, uint32_t id, int res, cons
}
static inline void
-pw_client_proxy_get_permissions(struct pw_client_proxy *client)
+pw_client_proxy_get_permissions(struct pw_client_proxy *client, uint32_t index, uint32_t num)
{
- pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions);
+ pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions, index, num);
}
static inline void
-pw_client_proxy_update_permissions(struct pw_client_proxy *client, const struct spa_dict *dict)
+pw_client_proxy_update_permissions(struct pw_client_proxy *client, uint32_t n_permissions,
+ const struct pw_permission *permissions)
{
- pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions, dict);
+ pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions,
+ n_permissions, permissions);
}
#define PW_VERSION_LINK 0
diff --git a/src/pipewire/permission.h b/src/pipewire/permission.h
new file mode 100644
index 00000000..8919dcf1
--- /dev/null
+++ b/src/pipewire/permission.h
@@ -0,0 +1,60 @@
+/* PipeWire
+ * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __PIPEWIRE_PERMISSION_H__
+#define __PIPEWIRE_PERMISSION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <spa/utils/defs.h>
+
+/** \class pw_permission
+ *
+ * \brief a PipeWire permission
+ *
+ * Permissions are kept for a client and describe what the client is
+ * allowed to do with an object.
+ *
+ * See \ref page_core_api
+ */
+
+#define PW_PERM_R 0400 /**< object can be seen and events can be received */
+#define PW_PERM_W 0200 /**< methods can be called that modify the object */
+#define PW_PERM_X 0100 /**< methods can be called on the object. The W flag must be
+ * present in order to call methods that modify the object. */
+#define PW_PERM_RWX (PW_PERM_R|PW_PERM_W|PW_PERM_X)
+
+#define PW_PERM_IS_R(p) (((p)&PW_PERM_R) == PW_PERM_R)
+#define PW_PERM_IS_W(p) (((p)&PW_PERM_W) == PW_PERM_W)
+#define PW_PERM_IS_X(p) (((p)&PW_PERM_X) == PW_PERM_X)
+
+struct pw_permission {
+ uint32_t id; /**< id of object, SPA_ID_INVALID for default permission */
+ uint32_t permissions; /**< bitmask of above permissions */
+};
+
+#define PW_PERMISSION_INIT(id,p) (struct pw_permission){ (id), (p) }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __PIPEWIRE_PERMISSION_H__ */
diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c
index 1c6838d6..212717c8 100644
--- a/src/tools/pipewire-cli.c
+++ b/src/tools/pipewire-cli.c
@@ -32,6 +32,7 @@
#include <pipewire/command.h>
#include <pipewire/interfaces.h>
#include <pipewire/type.h>
+#include <pipewire/permission.h>
static const char WHITESPACE[] = " \t";
@@ -1164,15 +1165,15 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
static bool do_permissions(struct data *data, const char *cmd, char *args, char **error)
{
struct remote_data *rd = data->current;
- char *a[2];
+ char *a[3];
int n;
uint32_t id;
struct global *global;
- struct spa_dict_item items[1];
+ struct pw_permission permissions[1];
- n = pw_split_ip(args, WHITESPACE, 2, a);
- if (n < 2) {
- asprintf(error, "%s <client-id> <permission>", cmd);
+ n = pw_split_ip(args, WHITESPACE, 3, a);
+ if (n < 3) {
+ asprintf(error, "%s <client-id> <object> <permission>", cmd);
return false;
}
@@ -1191,9 +1192,11 @@ static bool do_permissions(struct data *data, const char *cmd, char *args, char
return false;
}
- items[0] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, a[1]);
+
+ permissions[0] = PW_PERMISSION_INIT(atoi(a[1]), atoi(a[2]));
+
pw_client_proxy_update_permissions((struct pw_client_proxy*)global->proxy,
- &SPA_DICT_INIT(items, 1));
+ 1, permissions);
return true;
}