access: rework access checks

Remove the access struct. Allow for the access module to override any
method of a resource to do additional checks.
This commit is contained in:
Wim Taymans 2017-06-12 18:20:59 +02:00
parent 2c1245f8ef
commit 611ce2151e
14 changed files with 192 additions and 300 deletions

View file

@ -528,11 +528,18 @@ struct pw_client_node_events {
* The transport area is used to exchange real-time commands between
* the client and the server.
*
* \param readfd fd for signal data can be read
* \param writefd fd for signal data can be written
* \param memfd the memory fd of the area
* \param offset the offset to map
* \param size the size to map
*/
void (*transport) (void *object, int readfd, int writefd, int memfd, uint32_t offset, uint32_t size);
void (*transport) (void *object,
int readfd,
int writefd,
int memfd,
uint32_t offset,
uint32_t size);
};
#define pw_client_node_notify_set_props(r,...) ((struct pw_client_node_events*)r->iface->events)->props(r,__VA_ARGS__)

View file

@ -29,7 +29,9 @@
#include <dbus/dbus.h>
#include "pipewire/client/interfaces.h"
#include "pipewire/client/utils.h"
#include "pipewire/server/core.h"
#include "pipewire/server/module.h"
@ -43,7 +45,6 @@ struct impl {
struct pw_listener global_removed;
struct spa_list client_list;
struct pw_access access;
struct spa_source *dispatch_event;
};
@ -53,15 +54,23 @@ struct client_info {
struct spa_list link;
struct pw_client *client;
bool is_sandboxed;
const struct pw_core_methods *old_methods;
struct pw_core_methods core_methods;
struct spa_list async_pending;
struct pw_listener resource_added;
struct pw_listener resource_removed;
};
struct async_pending {
struct spa_list link;
bool handled;
struct client_info *info;
bool handled;
char *handle;
struct pw_access_data *access_data;
struct pw_resource *resource;
char *factory_name;
char *name;
struct pw_properties *properties;
uint32_t new_id;
};
static struct client_info *find_client_info(struct impl *impl, struct pw_client *client)
@ -106,44 +115,28 @@ static struct async_pending *find_pending(struct client_info *cinfo, const char
return NULL;
}
static void free_pending(struct pw_access_data *d)
static void free_pending(struct async_pending *p)
{
struct async_pending *p = d->user_data;
if (!p->handled)
close_request(p);
pw_log_debug("pending %p: handle %s", p, p->handle);
spa_list_remove(&p->link);
free(p->handle);
}
static void
add_pending(struct client_info *cinfo, const char *handle, struct pw_access_data *access_data)
{
struct async_pending *p;
struct pw_access_data *ad;
ad = access_data->async_start(access_data, sizeof(struct async_pending));
ad->free = free_pending;
p = ad->user_data;
p->info = cinfo;
p->handle = strdup(handle);
p->access_data = ad;
p->handled = false;
pw_log_debug("pending %p: handle %s", p, handle);
spa_list_insert(cinfo->async_pending.prev, &p->link);
free(p->factory_name);
free(p->name);
if (p->properties)
pw_properties_free(p->properties);
free(p);
}
static void client_info_free(struct client_info *cinfo)
{
struct async_pending *p, *tmp;
spa_list_for_each_safe(p, tmp, &cinfo->async_pending, link) {
p->access_data->complete(p->access_data, SPA_RESULT_NO_PERMISSION);
}
spa_list_for_each_safe(p, tmp, &cinfo->async_pending, link)
free_pending(p);
spa_list_remove(&cinfo->link);
free(cinfo);
}
@ -221,8 +214,8 @@ check_global_owner(struct pw_core *core, struct pw_client *client, struct pw_glo
return false;
}
static int
do_view_global(struct pw_access *access, struct pw_client *client, struct pw_global *global)
static bool
do_global_filter(struct pw_global *global, struct pw_client *client, void *data)
{
if (global->type == client->core->type.link) {
struct pw_link *link = global->object;
@ -230,15 +223,15 @@ do_view_global(struct pw_access *access, struct pw_client *client, struct pw_glo
/* we must be able to see both nodes */
if (link->output
&& !check_global_owner(client->core, client, link->output->node->global))
return SPA_RESULT_ERROR;
return false;
if (link->input
&& !check_global_owner(client->core, client, link->input->node->global))
return SPA_RESULT_ERROR;
return false;
} else if (!check_global_owner(client->core, client, global))
return SPA_RESULT_ERROR;
return false;
return SPA_RESULT_OK;
return true;
}
static DBusHandlerResult
@ -250,7 +243,6 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
uint32_t response = 2;
DBusError error;
struct async_pending *p;
struct pw_access_data *d;
dbus_error_init(&error);
@ -267,26 +259,39 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data)
return DBUS_HANDLER_RESULT_HANDLED;
p->handled = true;
d = p->access_data;
pw_log_debug("portal check result: %d", response);
d->complete(d, response == 0 ? SPA_RESULT_OK : SPA_RESULT_NO_PERMISSION);
if (response == 0) {
cinfo->old_methods->create_node (p->resource,
p->factory_name,
p->name,
&p->properties->dict,
p->new_id);
} else {
pw_core_notify_error(cinfo->client->core_resource,
p->resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
}
free_pending(p);
pw_client_set_busy(cinfo->client, false);
return DBUS_HANDLER_RESULT_HANDLED;
}
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
static int
do_create_node(struct pw_access *access,
struct pw_access_data *data,
const char *factory_name,
const char *name,
struct pw_properties *properties)
static void do_create_node(void *object,
const char *factory_name,
const char *name,
const struct spa_dict *props,
uint32_t new_id)
{
struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access);
struct client_info *cinfo = find_client_info(impl, data->resource->client);
struct pw_resource *resource = object;
struct client_info *cinfo = resource->access_private;
struct impl *impl = cinfo->impl;
struct pw_client *client = resource->client;
DBusMessage *m = NULL, *r = NULL;
DBusError error;
pid_t pid;
@ -294,14 +299,15 @@ do_create_node(struct pw_access *access,
DBusMessageIter dict_iter;
const char *handle;
const char *device;
struct async_pending *p;
if (!cinfo->is_sandboxed) {
data->complete(data, SPA_RESULT_OK);
return SPA_RESULT_OK;
cinfo->old_methods->create_node (object, factory_name, name, props, new_id);
return;
}
if (strcmp(factory_name, "client-node") != 0) {
data->complete(data, SPA_RESULT_NO_PERMISSION);
return SPA_RESULT_NO_PERMISSION;
pw_log_error("can only allow client-node");
goto not_allowed;
}
pw_log_info("ask portal for client %p", cinfo->client);
@ -345,61 +351,93 @@ do_create_node(struct pw_access *access,
dbus_connection_add_filter(impl->bus, portal_response, cinfo, NULL);
add_pending(cinfo, handle, data);
p = calloc(1, sizeof(struct async_pending));
p->info = cinfo;
p->handle = strdup(handle);
p->handled = false;
p->resource = resource;
p->factory_name = strdup(factory_name);
p->name = strdup(name);
p->properties = props ? pw_properties_new_dict(props) : NULL;
p->new_id = new_id;
pw_client_set_busy(client, true);
return SPA_RESULT_RETURN_ASYNC(0);
pw_log_debug("pending %p: handle %s", p, handle);
spa_list_insert(cinfo->async_pending.prev, &p->link);
return;
no_method_call:
pw_log_error("Failed to create message");
return SPA_RESULT_NO_PERMISSION;
goto not_allowed;
message_failed:
dbus_message_unref(m);
return SPA_RESULT_NO_PERMISSION;
goto not_allowed;
send_failed:
pw_log_error("Failed to call portal: %s", error.message);
dbus_error_free(&error);
dbus_message_unref(m);
return SPA_RESULT_NO_PERMISSION;
goto not_allowed;
parse_failed:
pw_log_error("Failed to parse AccessDevice result: %s", error.message);
dbus_error_free(&error);
dbus_message_unref(r);
return SPA_RESULT_NO_PERMISSION;
goto not_allowed;
subscribe_failed:
pw_log_error("Failed to subscribe to Request signal: %s", error.message);
dbus_error_free(&error);
return SPA_RESULT_NO_PERMISSION;
goto not_allowed;
not_allowed:
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
return;
}
static int
do_create_link(struct pw_access *access,
struct pw_access_data *data,
static void
do_create_link(void *object,
uint32_t output_node_id,
uint32_t output_port_id,
uint32_t input_node_id,
uint32_t input_port_id,
const struct spa_format *filter,
const struct pw_properties *props)
const struct spa_dict *props,
uint32_t new_id)
{
struct impl *impl = SPA_CONTAINER_OF(access, struct impl, access);
struct client_info *cinfo = find_client_info(impl, data->resource->client);
int res;
struct pw_resource *resource = object;
struct client_info *cinfo = resource->access_private;
struct pw_client *client = resource->client;
if (cinfo->is_sandboxed)
res = SPA_RESULT_NO_PERMISSION;
else
res = SPA_RESULT_OK;
data->complete(data, res);
return SPA_RESULT_OK;
if (cinfo->is_sandboxed) {
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_NO_PERMISSION, "not allowed");
return;
}
cinfo->old_methods->create_link (object,
output_node_id,
output_port_id,
input_node_id,
input_port_id,
filter,
props,
new_id);
}
static void on_resource_added(struct pw_listener *listener,
struct pw_client *client,
struct pw_resource *resource)
{
struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_added);
struct impl *impl = cinfo->impl;
static struct pw_access access_checks = {
do_view_global,
do_create_node,
do_create_link,
};
if (resource->type == impl->core->type.core) {
cinfo->old_methods = resource->implementation;
cinfo->core_methods = *cinfo->old_methods;
resource->implementation = &cinfo->core_methods;
resource->access_private = cinfo;
cinfo->core_methods.create_node = do_create_node;
cinfo->core_methods.create_link = do_create_link;
}
}
static void
on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_global *global)
@ -417,6 +455,8 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl
cinfo->is_sandboxed = true;
spa_list_init(&cinfo->async_pending);
pw_signal_add(&client->resource_added, &cinfo->resource_added, on_resource_added);
spa_list_insert(impl->client_list.prev, &cinfo->link);
pw_log_debug("module %p: client %p added", impl, client);
@ -624,7 +664,6 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
impl->core = core;
impl->properties = properties;
impl->access = access_checks;
impl->bus = dbus_bus_get_private(DBUS_BUS_SESSION, &error);
if (impl->bus == NULL)
@ -640,12 +679,12 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope
toggle_timeout, impl, NULL);
dbus_connection_set_wakeup_main_function(impl->bus, wakeup_main, impl, NULL);
core->access = &impl->access;
spa_list_init(&impl->client_list);
pw_signal_add(&core->global_added, &impl->global_added, on_global_added);
pw_signal_add(&core->global_removed, &impl->global_removed, on_global_removed);
core->global_filter = do_global_filter;
core->global_filter_data = impl;
return impl;

View file

@ -1,20 +0,0 @@
/* 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.
*/
#include "pipewire/server/core.h"

View file

@ -1,70 +0,0 @@
/* 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_ACCESS_H__
#define __PIPEWIRE_ACCESS_H__
#ifdef __cplusplus
extern "C" {
#endif
#define PIPEWIRE_TYPE__Access "PipeWire:Object:Access"
#define PIPEWIRE_TYPE_ACCESS_BASE PIPEWIRE_TYPE__Access ":"
#include <pipewire/client/sig.h>
#include <pipewire/server/client.h>
#include <pipewire/server/resource.h>
struct pw_access_data {
struct pw_resource *resource;
void *(*async_start) (struct pw_access_data *data, size_t size);
void (*complete) (struct pw_access_data *data, int res);
void (*free) (struct pw_access_data *data);
void *user_data;
};
/**
* \struct pw_access
*
* PipeWire Access support struct.
*/
struct pw_access {
int (*view_global) (struct pw_access *access,
struct pw_client *client, struct pw_global *global);
int (*create_node) (struct pw_access *access,
struct pw_access_data *data,
const char *factory_name,
const char *name, struct pw_properties *properties);
int (*create_link) (struct pw_access *access,
struct pw_access_data *data,
uint32_t output_node_id,
uint32_t output_port_id,
uint32_t input_node_id,
uint32_t input_port_id,
const struct spa_format *filter,
const struct pw_properties *props);
};
#ifdef __cplusplus
}
#endif
#endif /* __PIPEWIRE_ACCESS_H__ */

View file

@ -1173,7 +1173,9 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client,
this->resource = pw_resource_new(client,
id,
client->core->type.client_node,
this, (pw_destroy_t) client_node_resource_destroy);
this,
&client_node_methods,
(pw_destroy_t) client_node_resource_destroy);
if (this->resource == NULL)
goto error_no_resource;
@ -1184,8 +1186,6 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client,
pw_signal_add(&this->node->loop_changed, &impl->loop_changed, on_loop_changed);
pw_signal_add(&impl->core->global_added, &impl->global_added, on_global_added);
this->resource->implementation = &client_node_methods;
return this;
error_no_resource:

View file

@ -43,7 +43,7 @@ client_bind_func(struct pw_global *global, struct pw_client *client, uint32_t ve
struct pw_client *this = global->object;
struct pw_resource *resource;
resource = pw_resource_new(client, id, global->type, global->object, client_unbind_func);
resource = pw_resource_new(client, id, global->type, global->object, NULL, client_unbind_func);
if (resource == NULL)
goto no_mem;

View file

@ -38,19 +38,16 @@ struct impl {
struct spa_support support[4];
};
struct access_create_node {
struct pw_access_data data;
char *factory_name;
char *name;
struct pw_properties *properties;
uint32_t new_id;
bool async;
};
/** \endcond */
#define ACCESS_VIEW_GLOBAL(client,global) (client->core->access == NULL || \
client->core->access->view_global (client->core->access, \
client, global) == SPA_RESULT_OK)
static bool pw_global_is_visible(struct pw_global *global,
struct pw_client *client)
{
struct pw_core *core = client->core;
return (core->global_filter == NULL ||
core->global_filter(global, client, core->global_filter_data));
}
static void registry_bind(void *object, uint32_t id, uint32_t version, uint32_t new_id)
{
@ -66,7 +63,7 @@ static void registry_bind(void *object, uint32_t id, uint32_t version, uint32_t
if (&global->link == &core->global_list)
goto no_id;
if (!ACCESS_VIEW_GLOBAL(client, global))
if (!pw_global_is_visible(global, client))
goto no_id;
pw_log_debug("global %p: bind object id %d to %d", global, id, new_id);
@ -118,16 +115,17 @@ static void core_get_registry(void *object, uint32_t new_id)
registry_resource = pw_resource_new(client,
new_id,
this->type.registry, this, destroy_registry_resource);
this->type.registry,
this,
&registry_methods,
destroy_registry_resource);
if (registry_resource == NULL)
goto no_mem;
registry_resource->implementation = &registry_methods;
spa_list_insert(this->registry_resource_list.prev, &registry_resource->link);
spa_list_for_each(global, &this->global_list, link) {
if (ACCESS_VIEW_GLOBAL(client, global))
if (pw_global_is_visible(global, client))
pw_registry_notify_global(registry_resource,
global->id,
spa_type_map_get_type(this->type.map,
@ -143,73 +141,6 @@ static void core_get_registry(void *object, uint32_t new_id)
resource->id, SPA_RESULT_NO_MEMORY, "no memory");
}
static void *async_create_node_start(struct pw_access_data *data, size_t size)
{
struct access_create_node *d;
struct pw_client *client = data->resource->client;
d = calloc(1, sizeof(struct access_create_node) + size);
memcpy(d, data, sizeof(struct access_create_node));
d->factory_name = strdup(d->factory_name);
d->name = strdup(d->name);
d->async = true;
d->data.user_data = SPA_MEMBER(d, sizeof(struct access_create_node), void);
pw_client_set_busy(client, true);
return d;
}
static void async_create_node_free(struct pw_access_data *data)
{
struct access_create_node *d = (struct access_create_node *) data;
if (d->properties)
pw_properties_free(d->properties);
if (d->async) {
if (d->data.free)
d->data.free(&d->data);
free(d->factory_name);
free(d->name);
free(d);
}
}
static void async_create_node_complete(struct pw_access_data *data, int res)
{
struct access_create_node *d = (struct access_create_node *) data;
struct pw_resource *resource = d->data.resource;
struct pw_client *client = resource->client;
struct pw_node_factory *factory;
if (res != SPA_RESULT_OK)
goto denied;
factory = pw_core_find_node_factory(client->core, d->factory_name);
if (factory == NULL)
goto no_factory;
/* error will be posted */
pw_node_factory_create_node(factory, client, d->name, d->properties, d->new_id);
d->properties = NULL;
goto done;
no_factory:
pw_log_error("can't find node factory");
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name");
goto done;
denied:
pw_log_error("create node refused %d", res);
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_NO_PERMISSION, "operation not allowed");
done:
async_create_node_free(&d->data);
pw_client_set_busy(client, false);
return;
}
static void
core_create_node(void *object,
const char *factory_name,
@ -219,47 +150,39 @@ core_create_node(void *object,
{
struct pw_resource *resource = object;
struct pw_client *client = resource->client;
int i;
struct pw_node_factory *factory;
struct pw_properties *properties;
struct access_create_node access_data;
int res;
int i;
factory = pw_core_find_node_factory(client->core, factory_name);
if (factory == NULL)
goto no_factory;
properties = pw_properties_new(NULL, NULL);
if (properties == NULL)
goto no_mem;
for (i = 0; i < props->n_items; i++) {
for (i = 0; i < props->n_items; i++)
pw_properties_set(properties, props->items[i].key, props->items[i].value);
}
access_data.data.resource = resource;
access_data.data.async_start = async_create_node_start;
access_data.data.complete = async_create_node_complete;
access_data.data.free = NULL;
access_data.factory_name = (char *) factory_name;
access_data.name = (char *) name;
access_data.properties = properties;
access_data.new_id = new_id;
access_data.async = false;
/* error will be posted */
pw_node_factory_create_node(factory, client, name, properties, new_id);
properties = NULL;
if (client->core->access) {
res = client->core->access->create_node(client->core->access,
&access_data.data,
factory_name,
name,
properties);
} else {
res = SPA_RESULT_OK;
}
if (!SPA_RESULT_IS_ASYNC(res))
async_create_node_complete(&access_data.data, res);
done:
return;
no_factory:
pw_log_error("can't find node factory");
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name");
goto done;
no_mem:
pw_log_error("can't create client node");
pw_log_error("can't create properties");
pw_core_notify_error(client->core_resource,
resource->id, SPA_RESULT_NO_MEMORY, "no memory");
return;
goto done;
}
static void
@ -294,7 +217,7 @@ static void core_update_types(void *object, uint32_t first_id, uint32_t n_types,
}
}
static struct pw_core_methods core_methods = {
static const struct pw_core_methods core_methods = {
&core_update_types,
&core_sync,
&core_get_registry,
@ -316,12 +239,10 @@ core_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers
struct pw_core *this = global->object;
struct pw_resource *resource;
resource = pw_resource_new(client, id, global->type, global->object, core_unbind_func);
resource = pw_resource_new(client, id, global->type, global->object, &core_methods, core_unbind_func);
if (resource == NULL)
goto no_mem;
resource->implementation = &core_methods;
spa_list_insert(this->resource_list.prev, &resource->link);
client->core_resource = resource;
@ -483,8 +404,8 @@ pw_core_add_global(struct pw_core *core,
pw_log_debug("global %p: new %u %s, owner %p", this, this->id, type_name, owner);
spa_list_for_each(registry, &core->registry_resource_list, link)
if (ACCESS_VIEW_GLOBAL(registry->client, this))
pw_registry_notify_global(registry, this->id, type_name, this->version);
if (pw_global_is_visible(this, registry->client))
pw_registry_notify_global(registry, this->id, type_name, this->version);
return true;
}
@ -533,8 +454,8 @@ void pw_global_destroy(struct pw_global *global)
pw_signal_emit(&global->destroy_signal, global);
spa_list_for_each(registry, &core->registry_resource_list, link)
if (ACCESS_VIEW_GLOBAL(registry->client, global))
pw_registry_notify_global_remove(registry, global->id);
if (pw_global_is_visible(global, registry->client))
pw_registry_notify_global_remove(registry, global->id);
pw_map_remove(&core->objects, global->id);

View file

@ -29,7 +29,8 @@ extern "C" {
struct pw_global;
#include <pipewire/client/type.h>
#include <pipewire/server/access.h>
#include <pipewire/client/interfaces.h>
#include <pipewire/server/main-loop.h>
#include <pipewire/server/data-loop.h>
#include <pipewire/server/node.h>
@ -87,6 +88,9 @@ struct pw_global;
typedef int (*pw_bind_func_t) (struct pw_global *global,
struct pw_client *client, uint32_t version, uint32_t id);
typedef bool (*pw_global_filter_func_t) (struct pw_global *global,
struct pw_client *client, void *data);
/** \page page_global Global
*
* Global objects represent resources that are available on the server and
@ -141,7 +145,9 @@ struct pw_core {
struct pw_properties *properties; /**< properties of the core */
struct pw_type type; /**< type map and common types */
struct pw_access *access; /**< access control checks */
pw_global_filter_func_t global_filter;
void *global_filter_data;
struct pw_map objects; /**< map of known objects */

View file

@ -834,7 +834,7 @@ link_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers
struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this);
struct pw_resource *resource;
resource = pw_resource_new(client, id, global->type, global->object, link_unbind_func);
resource = pw_resource_new(client, id, global->type, global->object, NULL, link_unbind_func);
if (resource == NULL)
goto no_mem;

View file

@ -1,5 +1,4 @@
pipewirecore_headers = [
'access.h',
'client.h',
'client-node.h',
'command.h',
@ -17,7 +16,6 @@ pipewirecore_headers = [
]
pipewirecore_sources = [
'access.c',
'client.c',
'client-node.c',
'command.c',

View file

@ -92,7 +92,7 @@ module_bind_func(struct pw_global *global, struct pw_client *client, uint32_t ve
struct pw_module *this = global->object;
struct pw_resource *resource;
resource = pw_resource_new(client, id, global->type, global->object, NULL);
resource = pw_resource_new(client, id, global->type, global->object, NULL, NULL);
if (resource == NULL)
goto no_mem;

View file

@ -465,7 +465,7 @@ node_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers
struct pw_node *this = global->object;
struct pw_resource *resource;
resource = pw_resource_new(client, id, global->type, global->object, node_unbind_func);
resource = pw_resource_new(client, id, global->type, global->object, NULL, node_unbind_func);
if (resource == NULL)
goto no_mem;

View file

@ -29,7 +29,11 @@ struct impl {
/** \endcond */
struct pw_resource *pw_resource_new(struct pw_client *client,
uint32_t id, uint32_t type, void *object, pw_destroy_t destroy)
uint32_t id,
uint32_t type,
void *object,
const void *implementation,
pw_destroy_t destroy)
{
struct impl *impl;
struct pw_resource *this;
@ -43,6 +47,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client,
this->client = client;
this->type = type;
this->object = object;
this->implementation = implementation;
this->destroy = destroy;
pw_signal_init(&this->destroy_signal);

View file

@ -70,13 +70,19 @@ struct pw_resource {
const struct pw_interface *iface; /**< protocol specific interface functions */
const void *implementation; /**< implementation */
void *access_private; /**< private data for access control */
/** Emited when the resource is destroyed */
PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_resource *resource));
};
struct pw_resource *
pw_resource_new(struct pw_client *client,
uint32_t id, uint32_t type, void *object, pw_destroy_t destroy);
uint32_t id,
uint32_t type,
void *object,
const void *implementation,
pw_destroy_t destroy);
void
pw_resource_destroy(struct pw_resource *resource);