mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	protocol: add more methods on client
Add method to get and set permissions on a client Add method to send error to client.
This commit is contained in:
		
							parent
							
								
									bbf718cc98
								
							
						
					
					
						commit
						e026f55c97
					
				
					 6 changed files with 410 additions and 46 deletions
				
			
		| 
						 | 
					@ -1017,6 +1017,155 @@ static int client_demarshal_info(void *object, void *data, size_t size)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_marshal_permissions(void *object, const struct spa_dict *dict)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
 | 
						uint32_t i, n_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < n_items; i++) {
 | 
				
			||||||
 | 
							spa_pod_builder_add(b,
 | 
				
			||||||
 | 
									    "s", dict->items[i].key,
 | 
				
			||||||
 | 
									    "s", dict->items[i].value, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spa_pod_builder_add(b, "]", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_protocol_native_end_resource(resource, b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int client_demarshal_permissions(void *object, void *data, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
 | 
						struct spa_dict props;
 | 
				
			||||||
 | 
						struct spa_pod_parser prs;
 | 
				
			||||||
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_parser_init(&prs, data, size, 0);
 | 
				
			||||||
 | 
						if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
 | 
				
			||||||
 | 
						for (i = 0; i < props.n_items; i++) {
 | 
				
			||||||
 | 
							if (spa_pod_parser_get(&prs,
 | 
				
			||||||
 | 
									"s", &props.items[i].key,
 | 
				
			||||||
 | 
									"s", &props.items[i].value,
 | 
				
			||||||
 | 
									NULL) < 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pw_proxy_notify(proxy, struct pw_client_proxy_events, permissions, 0, &props);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_marshal_error(void *object, uint32_t id, int res, const char *error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						b = pw_protocol_native_begin_proxy(proxy, PW_CLIENT_PROXY_METHOD_ERROR);
 | 
				
			||||||
 | 
						spa_pod_builder_add_struct(b,
 | 
				
			||||||
 | 
								       "i", id,
 | 
				
			||||||
 | 
								       "i", res,
 | 
				
			||||||
 | 
								       "s", error);
 | 
				
			||||||
 | 
						pw_protocol_native_end_proxy(proxy, b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int client_demarshal_error(void *object, void *data, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct spa_pod_parser prs;
 | 
				
			||||||
 | 
						uint32_t id, res;
 | 
				
			||||||
 | 
						const char *error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_parser_init(&prs, data, size, 0);
 | 
				
			||||||
 | 
						if (spa_pod_parser_get(&prs,
 | 
				
			||||||
 | 
								"[ i", &id,
 | 
				
			||||||
 | 
								  "i", &res,
 | 
				
			||||||
 | 
								  "s", &error, NULL) < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_resource_do(resource, struct pw_client_proxy_methods, error, 0, id, res, error);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_marshal_get_permissions(void *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_protocol_native_end_proxy(proxy, b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int client_demarshal_get_permissions(void *object, void *data, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct spa_pod_parser prs;
 | 
				
			||||||
 | 
						void *ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_parser_init(&prs, data, size, 0);
 | 
				
			||||||
 | 
						if (spa_pod_parser_get(&prs, "[P]", &ptr, NULL) < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_resource_do(resource, struct pw_client_proxy_methods, get_permissions, 0);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_marshal_update_permissions(void *object, const struct spa_dict *props)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
 | 
						int i, n_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < n_items; i++) {
 | 
				
			||||||
 | 
							spa_pod_builder_add(b,
 | 
				
			||||||
 | 
									    "s", props->items[i].key,
 | 
				
			||||||
 | 
									    "s", props->items[i].value, NULL);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						spa_pod_builder_add(b, "]", NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_protocol_native_end_proxy(proxy, b);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int client_demarshal_update_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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_pod_parser_init(&prs, data, size, 0);
 | 
				
			||||||
 | 
						if (spa_pod_parser_get(&prs, "[ i", &props.n_items, NULL) < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						props.items = alloca(props.n_items * sizeof(struct spa_dict_item));
 | 
				
			||||||
 | 
						for (i = 0; i < props.n_items; i++) {
 | 
				
			||||||
 | 
							if (spa_pod_parser_get(&prs,
 | 
				
			||||||
 | 
									"s", &props.items[i].key,
 | 
				
			||||||
 | 
									"s", &props.items[i].value,
 | 
				
			||||||
 | 
									NULL) < 0)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pw_resource_do(resource, struct pw_client_proxy_methods, update_permissions, 0, &props);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void link_marshal_info(void *object, struct pw_link_info *info)
 | 
					static void link_marshal_info(void *object, struct pw_link_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
| 
						 | 
					@ -1342,19 +1491,36 @@ static const struct pw_protocol_marshal pw_protocol_native_port_marshal = {
 | 
				
			||||||
	PW_PORT_PROXY_EVENT_NUM,
 | 
						PW_PORT_PROXY_EVENT_NUM,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_client_proxy_methods pw_protocol_native_client_method_marshal = {
 | 
				
			||||||
 | 
						PW_VERSION_CLIENT_PROXY_METHODS,
 | 
				
			||||||
 | 
						&client_marshal_error,
 | 
				
			||||||
 | 
						&client_marshal_get_permissions,
 | 
				
			||||||
 | 
						&client_marshal_update_permissions,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_protocol_native_demarshal pw_protocol_native_client_method_demarshal[] = {
 | 
				
			||||||
 | 
						{ &client_demarshal_error, PW_PROTOCOL_NATIVE_PERM_W, },
 | 
				
			||||||
 | 
						{ &client_demarshal_get_permissions, 0, },
 | 
				
			||||||
 | 
						{ &client_demarshal_update_permissions, PW_PROTOCOL_NATIVE_PERM_W, },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pw_client_proxy_events pw_protocol_native_client_event_marshal = {
 | 
					static const struct pw_client_proxy_events pw_protocol_native_client_event_marshal = {
 | 
				
			||||||
	PW_VERSION_CLIENT_PROXY_EVENTS,
 | 
						PW_VERSION_CLIENT_PROXY_EVENTS,
 | 
				
			||||||
	&client_marshal_info,
 | 
						&client_marshal_info,
 | 
				
			||||||
 | 
						&client_marshal_permissions,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pw_protocol_native_demarshal pw_protocol_native_client_event_demarshal[] = {
 | 
					static const struct pw_protocol_native_demarshal pw_protocol_native_client_event_demarshal[] = {
 | 
				
			||||||
	{ &client_demarshal_info, 0, },
 | 
						{ &client_demarshal_info, 0, },
 | 
				
			||||||
 | 
						{ &client_demarshal_permissions, 0, }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct pw_protocol_marshal pw_protocol_native_client_marshal = {
 | 
					static const struct pw_protocol_marshal pw_protocol_native_client_marshal = {
 | 
				
			||||||
	PW_TYPE_INTERFACE_Client,
 | 
						PW_TYPE_INTERFACE_Client,
 | 
				
			||||||
	PW_VERSION_CLIENT,
 | 
						PW_VERSION_CLIENT,
 | 
				
			||||||
	NULL, NULL, 0,
 | 
						&pw_protocol_native_client_method_marshal,
 | 
				
			||||||
 | 
						pw_protocol_native_client_method_demarshal,
 | 
				
			||||||
 | 
						PW_CLIENT_PROXY_METHOD_NUM,
 | 
				
			||||||
	&pw_protocol_native_client_event_marshal,
 | 
						&pw_protocol_native_client_event_marshal,
 | 
				
			||||||
	pw_protocol_native_client_event_demarshal,
 | 
						pw_protocol_native_client_event_demarshal,
 | 
				
			||||||
	PW_CLIENT_PROXY_EVENT_NUM,
 | 
						PW_CLIENT_PROXY_EVENT_NUM,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,21 +47,42 @@ struct resource_data {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** find a specific permission for a global or NULL when there is none */
 | 
					/** find a specific permission for a global or NULL when there is none */
 | 
				
			||||||
static struct permission *
 | 
					static struct permission *
 | 
				
			||||||
find_permission(struct pw_client *client, struct pw_global *global)
 | 
					find_permission(struct pw_client *client, uint32_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
						struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
				
			||||||
	struct permission *p;
 | 
						struct permission *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!pw_array_check_index(&impl->permissions, global->id, struct permission))
 | 
						if (!pw_array_check_index(&impl->permissions, id, struct permission))
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = pw_array_get_unchecked(&impl->permissions, global->id, struct permission);
 | 
						p = pw_array_get_unchecked(&impl->permissions, id, struct permission);
 | 
				
			||||||
	if (p->permissions == -1)
 | 
						if (p->permissions == -1)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return p;
 | 
							return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct permission *ensure_permissions(struct pw_client *client, uint32_t id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
				
			||||||
 | 
						struct permission *p;
 | 
				
			||||||
 | 
						size_t len, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						len = pw_array_get_len(&impl->permissions, struct permission);
 | 
				
			||||||
 | 
						if (len <= id) {
 | 
				
			||||||
 | 
							size_t diff = id - len + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							p = pw_array_add(&impl->permissions, diff * sizeof(struct 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);
 | 
				
			||||||
 | 
						return p;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					/** \endcond */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t
 | 
					static uint32_t
 | 
				
			||||||
| 
						 | 
					@ -71,13 +92,111 @@ client_permission_func(struct pw_global *global,
 | 
				
			||||||
	struct impl *impl = data;
 | 
						struct impl *impl = data;
 | 
				
			||||||
	struct permission *p;
 | 
						struct permission *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = find_permission(client, global);
 | 
						p = find_permission(client, global->id);
 | 
				
			||||||
	if (p == NULL)
 | 
						if (p == NULL)
 | 
				
			||||||
		return impl->permissions_default;
 | 
							return impl->permissions_default;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return p->permissions;
 | 
							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;
 | 
				
			||||||
 | 
						struct resource_data *data = pw_resource_get_user_data(resource);
 | 
				
			||||||
 | 
						struct pw_client *client = data->client;
 | 
				
			||||||
 | 
						pw_resource_error(client->core_resource, id, res, error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_get_permissions(void *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct resource_data *data = pw_resource_get_user_data(resource);
 | 
				
			||||||
 | 
						struct pw_client *client = data->client;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void client_update_permissions(void *object, const struct spa_dict *props)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						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);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (impl->permissions_default != 0)
 | 
				
			||||||
 | 
							pw_client_set_busy(client, false);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_client_proxy_methods client_methods = {
 | 
				
			||||||
 | 
						PW_VERSION_CLIENT_PROXY_METHODS,
 | 
				
			||||||
 | 
						.error = client_error,
 | 
				
			||||||
 | 
						.get_permissions = client_get_permissions,
 | 
				
			||||||
 | 
						.update_permissions = client_update_permissions
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_unbind_func(void *data)
 | 
					static void client_unbind_func(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = data;
 | 
						struct pw_resource *resource = data;
 | 
				
			||||||
| 
						 | 
					@ -89,7 +208,6 @@ static const struct pw_resource_events resource_events = {
 | 
				
			||||||
	.destroy = client_unbind_func,
 | 
						.destroy = client_unbind_func,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
global_bind(void *_data, struct pw_client *client, uint32_t permissions,
 | 
					global_bind(void *_data, struct pw_client *client, uint32_t permissions,
 | 
				
			||||||
		 uint32_t version, uint32_t id)
 | 
							 uint32_t version, uint32_t id)
 | 
				
			||||||
| 
						 | 
					@ -131,7 +249,7 @@ core_global_removed(void *data, struct pw_global *global)
 | 
				
			||||||
	struct pw_client *client = &impl->this;
 | 
						struct pw_client *client = &impl->this;
 | 
				
			||||||
	struct permission *p;
 | 
						struct permission *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = find_permission(client, global);
 | 
						p = find_permission(client, global->id);
 | 
				
			||||||
	pw_log_debug("client %p: global %d removed, %p", client, global->id, p);
 | 
						pw_log_debug("client %p: global %d removed, %p", client, global->id, p);
 | 
				
			||||||
	if (p != NULL)
 | 
						if (p != NULL)
 | 
				
			||||||
		p->permissions = -1;
 | 
							p->permissions = -1;
 | 
				
			||||||
| 
						 | 
					@ -385,21 +503,10 @@ static int do_permissions(void *data, struct pw_global *global)
 | 
				
			||||||
	struct pw_client *client = update->client;
 | 
						struct pw_client *client = update->client;
 | 
				
			||||||
	struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
						struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
				
			||||||
	struct permission *p;
 | 
						struct permission *p;
 | 
				
			||||||
	size_t len, i;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	len = pw_array_get_len(&impl->permissions, struct permission);
 | 
						p = ensure_permissions(client, global->id);
 | 
				
			||||||
	if (len <= global->id) {
 | 
					 | 
				
			||||||
		size_t diff = global->id - len + 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		p = pw_array_add(&impl->permissions, diff * sizeof(struct permission));
 | 
					 | 
				
			||||||
	if (p == NULL)
 | 
						if (p == NULL)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (i = 0; i < diff; i++)
 | 
					 | 
				
			||||||
			p[i].permissions = -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	p = pw_array_get_unchecked(&impl->permissions, global->id, struct permission);
 | 
					 | 
				
			||||||
	if (p->permissions == -1)
 | 
						if (p->permissions == -1)
 | 
				
			||||||
		p->permissions = impl->permissions_default;
 | 
							p->permissions = impl->permissions_default;
 | 
				
			||||||
	else if (update->only_new)
 | 
						else if (update->only_new)
 | 
				
			||||||
| 
						 | 
					@ -411,26 +518,6 @@ static int do_permissions(void *data, struct pw_global *global)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict)
 | 
					int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
						struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this);
 | 
				
			||||||
| 
						 | 
					@ -500,3 +587,11 @@ void pw_client_set_busy(struct pw_client *client, bool busy)
 | 
				
			||||||
		pw_client_events_busy_changed(client, 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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,6 +177,8 @@ void pw_client_add_listener(struct pw_client *client,
 | 
				
			||||||
  * started and no further processing is allowed to happen for the 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_busy(struct pw_client *client, bool busy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pw_client_set_permissions(struct pw_client *client, uint32_t permissions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -678,7 +678,8 @@ pw_factory_proxy_add_listener(struct pw_factory_proxy *factory,
 | 
				
			||||||
#define PW_VERSION_CLIENT			0
 | 
					#define PW_VERSION_CLIENT			0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PW_CLIENT_PROXY_EVENT_INFO		0
 | 
					#define PW_CLIENT_PROXY_EVENT_INFO		0
 | 
				
			||||||
#define PW_CLIENT_PROXY_EVENT_NUM		1
 | 
					#define PW_CLIENT_PROXY_EVENT_PERMISSIONS	1
 | 
				
			||||||
 | 
					#define PW_CLIENT_PROXY_EVENT_NUM		2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Client events */
 | 
					/** Client events */
 | 
				
			||||||
struct pw_client_proxy_events {
 | 
					struct pw_client_proxy_events {
 | 
				
			||||||
| 
						 | 
					@ -690,6 +691,14 @@ struct pw_client_proxy_events {
 | 
				
			||||||
	 * \param info info about the client
 | 
						 * \param info info about the client
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	void (*info) (void *object, struct pw_client_info *info);
 | 
						void (*info) (void *object, struct pw_client_info *info);
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Notify a client permission
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Event emited as a result of the get_permissions method.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * \param param the parameter
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*permissions) (void *object, const struct spa_dict *dict);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Client */
 | 
					/** Client */
 | 
				
			||||||
| 
						 | 
					@ -703,7 +712,59 @@ pw_client_proxy_add_listener(struct pw_client_proxy *client,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define pw_client_resource_info(r,...) pw_resource_notify(r,struct pw_client_proxy_events,info,__VA_ARGS__)
 | 
					#define pw_client_resource_info(r,...) pw_resource_notify(r,struct pw_client_proxy_events,info,__VA_ARGS__)
 | 
				
			||||||
 | 
					#define pw_client_resource_permissions(r,...) pw_resource_notify(r,struct pw_client_proxy_events,permissions,__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PW_CLIENT_PROXY_METHOD_ERROR			0
 | 
				
			||||||
 | 
					#define PW_CLIENT_PROXY_METHOD_GET_PERMISSIONS		1
 | 
				
			||||||
 | 
					#define PW_CLIENT_PROXY_METHOD_UPDATE_PERMISSIONS	2
 | 
				
			||||||
 | 
					#define PW_CLIENT_PROXY_METHOD_NUM			3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Client methods */
 | 
				
			||||||
 | 
					struct pw_client_proxy_methods {
 | 
				
			||||||
 | 
					#define PW_VERSION_CLIENT_PROXY_METHODS	0
 | 
				
			||||||
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Send an error to a client
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * \param id the global id to report the error on
 | 
				
			||||||
 | 
						 * \param res an errno style error code
 | 
				
			||||||
 | 
						 * \param error an error string
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*error) (void *object, uint32_t id, int res, const char *error);
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get client permissions
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * A permissions event will be emited with the permissions.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*get_permissions) (void *object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Update client permissions
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * \param dict list of permissions to update
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						void (*update_permissions) (void *object, const struct spa_dict *dict);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Client permissions */
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					pw_client_proxy_error(struct pw_client_proxy *client, uint32_t id, int res, const char *error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, error, id, res, error);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					pw_client_proxy_get_permissions(struct pw_client_proxy *client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, get_permissions);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					pw_client_proxy_update_permissions(struct pw_client_proxy *client, const struct spa_dict *dict)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pw_proxy_do((struct pw_proxy*)client, struct pw_client_proxy_methods, update_permissions, dict);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PW_VERSION_LINK			0
 | 
					#define PW_VERSION_LINK			0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -230,8 +230,9 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st
 | 
				
			||||||
		if (current == NULL || spa_pod_compare(current, format) != 0) {
 | 
							if (current == NULL || spa_pod_compare(current, format) != 0) {
 | 
				
			||||||
			pw_log_debug("link %p: output format change, renegotiate", this);
 | 
								pw_log_debug("link %p: output format change, renegotiate", this);
 | 
				
			||||||
			if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) {
 | 
								if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) {
 | 
				
			||||||
				spa_debug_format(2, NULL, current);
 | 
									if (current)
 | 
				
			||||||
				spa_debug_format(2, NULL, format);
 | 
										spa_debug_pod(2, NULL, current);
 | 
				
			||||||
 | 
									spa_debug_pod(2, NULL, format);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			pw_node_set_state(output->node, PW_NODE_STATE_SUSPENDED);
 | 
								pw_node_set_state(output->node, PW_NODE_STATE_SUSPENDED);
 | 
				
			||||||
			out_state = PW_PORT_STATE_CONFIGURE;
 | 
								out_state = PW_PORT_STATE_CONFIGURE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -177,6 +177,7 @@ static bool do_create_link(struct data *data, const char *cmd, char *args, char
 | 
				
			||||||
static bool do_export_node(struct data *data, const char *cmd, char *args, char **error);
 | 
					static bool do_export_node(struct data *data, const char *cmd, char *args, char **error);
 | 
				
			||||||
static bool do_node_params(struct data *data, const char *cmd, char *args, char **error);
 | 
					static bool do_node_params(struct data *data, const char *cmd, char *args, char **error);
 | 
				
			||||||
static bool do_port_params(struct data *data, const char *cmd, char *args, char **error);
 | 
					static bool do_port_params(struct data *data, const char *cmd, char *args, char **error);
 | 
				
			||||||
 | 
					static bool do_permissions(struct data *data, const char *cmd, char *args, char **error);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct command command_list[] = {
 | 
					static struct command command_list[] = {
 | 
				
			||||||
	{ "help", "Show this help", do_help },
 | 
						{ "help", "Show this help", do_help },
 | 
				
			||||||
| 
						 | 
					@ -194,6 +195,7 @@ static struct command command_list[] = {
 | 
				
			||||||
	{ "export-node", "Export a local node to the current remote. <node-id> [remote-var]", do_export_node },
 | 
						{ "export-node", "Export a local node to the current remote. <node-id> [remote-var]", do_export_node },
 | 
				
			||||||
	{ "node-params", "Enumerate params of a node <node-id> [<param-id-name>]", do_node_params },
 | 
						{ "node-params", "Enumerate params of a node <node-id> [<param-id-name>]", do_node_params },
 | 
				
			||||||
	{ "port-params", "Enumerate params of a port <port-id> [<param-id-name>]", do_port_params },
 | 
						{ "port-params", "Enumerate params of a port <port-id> [<param-id-name>]", do_port_params },
 | 
				
			||||||
 | 
						{ "permissions", "Set permissions for a client <client-id> <permissions>", do_permissions },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool do_help(struct data *data, const char *cmd, char *args, char **error)
 | 
					static bool do_help(struct data *data, const char *cmd, char *args, char **error)
 | 
				
			||||||
| 
						 | 
					@ -1133,10 +1135,10 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
 | 
				
			||||||
		asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
 | 
							asprintf(error, "%s <object-id> [<param-id-name>]", cmd);
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (n == 2)
 | 
						if (n < 2)
 | 
				
			||||||
		param_id = SPA_PARAM_List;
 | 
							param_id = SPA_PARAM_List;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		param_id = SPA_PARAM_List;
 | 
							param_id = atoi(a[1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	id = atoi(a[0]);
 | 
						id = atoi(a[0]);
 | 
				
			||||||
	global = pw_map_lookup(&rd->globals, id);
 | 
						global = pw_map_lookup(&rd->globals, id);
 | 
				
			||||||
| 
						 | 
					@ -1159,6 +1161,43 @@ static bool do_port_params(struct data *data, const char *cmd, char *args, char
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool do_permissions(struct data *data, const char *cmd, char *args, char **error)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct remote_data *rd = data->current;
 | 
				
			||||||
 | 
						char *a[2];
 | 
				
			||||||
 | 
					        int n;
 | 
				
			||||||
 | 
						uint32_t id;
 | 
				
			||||||
 | 
						struct global *global;
 | 
				
			||||||
 | 
						struct spa_dict_item items[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n = pw_split_ip(args, WHITESPACE, 2, a);
 | 
				
			||||||
 | 
						if (n < 2) {
 | 
				
			||||||
 | 
							asprintf(error, "%s <client-id> <permission>", cmd);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						id = atoi(a[0]);
 | 
				
			||||||
 | 
						global = pw_map_lookup(&rd->globals, id);
 | 
				
			||||||
 | 
						if (global == NULL) {
 | 
				
			||||||
 | 
							asprintf(error, "%s: unknown global %d", cmd, id);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (global->type != PW_TYPE_INTERFACE_Client) {
 | 
				
			||||||
 | 
							asprintf(error, "object %d is not a client", atoi(a[0]));
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (global->proxy == NULL) {
 | 
				
			||||||
 | 
							if (!bind_global(rd, global, error))
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						items[0] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, a[1]);
 | 
				
			||||||
 | 
						pw_client_proxy_update_permissions((struct pw_client_proxy*)global->proxy,
 | 
				
			||||||
 | 
								&SPA_DICT_INIT(items, 1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool parse(struct data *data, char *buf, size_t size, char **error)
 | 
					static bool parse(struct data *data, char *buf, size_t size, char **error)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *a[2];
 | 
						char *a[2];
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue