mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-31 22:25:38 -04:00
flatpak: add flatpak module
Pass LoopUtils to callbacks to make it easier to reschedule timeouts.
This commit is contained in:
parent
a5b39019d1
commit
be528ba7c2
17 changed files with 826 additions and 259 deletions
|
|
@ -376,8 +376,9 @@ static const PinosRegistryEvents registry_events = {
|
|||
typedef bool (*PinosDemarshalFunc) (void *object, void *data, size_t size);
|
||||
|
||||
static void
|
||||
do_flush_event (SpaSource *source,
|
||||
void *data)
|
||||
do_flush_event (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosContextImpl *impl = data;
|
||||
if (impl->connection)
|
||||
|
|
@ -394,10 +395,11 @@ on_need_flush (PinosListener *listener,
|
|||
}
|
||||
|
||||
static void
|
||||
on_context_data (SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
on_context_data (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
{
|
||||
PinosContextImpl *impl = data;
|
||||
PinosContext *this = &impl->this;
|
||||
|
|
|
|||
|
|
@ -35,21 +35,6 @@
|
|||
#include <pinos/client/loop.h>
|
||||
#include <pinos/client/log.h>
|
||||
|
||||
typedef struct {
|
||||
SpaSource source;
|
||||
SpaList link;
|
||||
|
||||
bool close;
|
||||
union {
|
||||
SpaSourceIOFunc io;
|
||||
SpaSourceIdleFunc idle;
|
||||
SpaSourceEventFunc event;
|
||||
SpaSourceTimerFunc timer;
|
||||
SpaSourceSignalFunc signal;
|
||||
} func;
|
||||
int signal_number;
|
||||
} SpaSourceImpl;
|
||||
|
||||
#define DATAS_SIZE (4096 * 8)
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -83,6 +68,24 @@ typedef struct {
|
|||
uint8_t buffer_data[DATAS_SIZE];
|
||||
} PinosLoopImpl;
|
||||
|
||||
typedef struct {
|
||||
SpaSource source;
|
||||
|
||||
PinosLoopImpl *impl;
|
||||
SpaList link;
|
||||
|
||||
bool close;
|
||||
union {
|
||||
SpaSourceIOFunc io;
|
||||
SpaSourceIdleFunc idle;
|
||||
SpaSourceEventFunc event;
|
||||
SpaSourceTimerFunc timer;
|
||||
SpaSourceSignalFunc signal;
|
||||
} func;
|
||||
int signal_number;
|
||||
bool enabled;
|
||||
} SpaSourceImpl;
|
||||
|
||||
static inline uint32_t
|
||||
spa_io_to_epoll (SpaIO mask)
|
||||
{
|
||||
|
|
@ -221,8 +224,9 @@ loop_invoke (SpaLoop *loop,
|
|||
}
|
||||
|
||||
static void
|
||||
event_func (SpaSource *source,
|
||||
void *data)
|
||||
event_func (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosLoopImpl *impl = data;
|
||||
uint32_t offset;
|
||||
|
|
@ -314,7 +318,7 @@ static void
|
|||
source_io_func (SpaSource *source)
|
||||
{
|
||||
SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, source);
|
||||
impl->func.io (source, source->fd, source->rmask, source->data);
|
||||
impl->func.io (&impl->impl->utils, source, source->fd, source->rmask, source->data);
|
||||
}
|
||||
|
||||
static SpaSource *
|
||||
|
|
@ -337,6 +341,7 @@ loop_add_io (SpaLoopUtils *utils,
|
|||
source->source.data = data;
|
||||
source->source.fd = fd;
|
||||
source->source.mask = mask;
|
||||
source->impl = impl;
|
||||
source->close = close;
|
||||
source->func.io = func;
|
||||
|
||||
|
|
@ -360,11 +365,12 @@ static void
|
|||
source_idle_func (SpaSource *source)
|
||||
{
|
||||
SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, source);
|
||||
impl->func.idle (source, source->data);
|
||||
impl->func.idle (&impl->impl->utils, source, source->data);
|
||||
}
|
||||
|
||||
static SpaSource *
|
||||
loop_add_idle (SpaLoopUtils *utils,
|
||||
bool enabled,
|
||||
SpaSourceIdleFunc func,
|
||||
void *data)
|
||||
{
|
||||
|
|
@ -379,6 +385,7 @@ loop_add_idle (SpaLoopUtils *utils,
|
|||
source->source.func = source_idle_func;
|
||||
source->source.data = data;
|
||||
source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
source->impl = impl;
|
||||
source->close = true;
|
||||
source->source.mask = SPA_IO_IN;
|
||||
source->func.idle = func;
|
||||
|
|
@ -387,7 +394,8 @@ loop_add_idle (SpaLoopUtils *utils,
|
|||
|
||||
spa_list_insert (&impl->source_list, &source->link);
|
||||
|
||||
spa_loop_utils_enable_idle (&impl->utils, &source->source, true);
|
||||
if (enabled)
|
||||
spa_loop_utils_enable_idle (&impl->utils, &source->source, true);
|
||||
|
||||
return &source->source;
|
||||
}
|
||||
|
|
@ -396,16 +404,18 @@ static void
|
|||
loop_enable_idle (SpaSource *source,
|
||||
bool enabled)
|
||||
{
|
||||
SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, source);
|
||||
uint64_t count;
|
||||
|
||||
if (enabled) {
|
||||
if (enabled && !impl->enabled) {
|
||||
count = 1;
|
||||
if (write (source->fd, &count, sizeof (uint64_t)) != sizeof (uint64_t))
|
||||
pinos_log_warn ("loop %p: failed to write idle fd: %s", source, strerror (errno));
|
||||
} else {
|
||||
} else if (!enabled && impl->enabled) {
|
||||
if (read (source->fd, &count, sizeof (uint64_t)) != sizeof (uint64_t))
|
||||
pinos_log_warn ("loop %p: failed to read idle fd: %s", source, strerror (errno));
|
||||
}
|
||||
impl->enabled = enabled;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -417,7 +427,7 @@ source_event_func (SpaSource *source)
|
|||
if (read (source->fd, &count, sizeof (uint64_t)) != sizeof (uint64_t))
|
||||
pinos_log_warn ("loop %p: failed to read event fd: %s", source, strerror (errno));
|
||||
|
||||
impl->func.event (source, source->data);
|
||||
impl->func.event (&impl->impl->utils, source, source->data);
|
||||
}
|
||||
|
||||
static SpaSource *
|
||||
|
|
@ -437,6 +447,7 @@ loop_add_event (SpaLoopUtils *utils,
|
|||
source->source.data = data;
|
||||
source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||
source->source.mask = SPA_IO_IN;
|
||||
source->impl = impl;
|
||||
source->close = true;
|
||||
source->func.event = func;
|
||||
|
||||
|
|
@ -465,7 +476,7 @@ source_timer_func (SpaSource *source)
|
|||
if (read (source->fd, &expires, sizeof (uint64_t)) != sizeof (uint64_t))
|
||||
pinos_log_warn ("loop %p: failed to read timer fd: %s", source, strerror (errno));
|
||||
|
||||
impl->func.timer (source, source->data);
|
||||
impl->func.timer (&impl->impl->utils, source, source->data);
|
||||
}
|
||||
|
||||
static SpaSource *
|
||||
|
|
@ -485,6 +496,7 @@ loop_add_timer (SpaLoopUtils *utils,
|
|||
source->source.data = data;
|
||||
source->source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
|
||||
source->source.mask = SPA_IO_IN;
|
||||
source->impl = impl;
|
||||
source->close = true;
|
||||
source->func.timer = func;
|
||||
|
||||
|
|
@ -532,7 +544,7 @@ source_signal_func (SpaSource *source)
|
|||
if (read (source->fd, &signal_info, sizeof (signal_info)) != sizeof (signal_info))
|
||||
pinos_log_warn ("loop %p: failed to read signal fd: %s", source, strerror (errno));
|
||||
|
||||
impl->func.signal (source, impl->signal_number, source->data);
|
||||
impl->func.signal (&impl->impl->utils, source, impl->signal_number, source->data);
|
||||
}
|
||||
|
||||
static SpaSource *
|
||||
|
|
@ -557,6 +569,7 @@ loop_add_signal (SpaLoopUtils *utils,
|
|||
source->source.fd = signalfd (-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
|
||||
sigprocmask (SIG_BLOCK, &mask, NULL);
|
||||
source->source.mask = SPA_IO_IN;
|
||||
source->impl = impl;
|
||||
source->close = true;
|
||||
source->func.signal = func;
|
||||
source->signal_number = signal_number;
|
||||
|
|
|
|||
|
|
@ -409,8 +409,9 @@ do_node_init (PinosStream *stream)
|
|||
}
|
||||
|
||||
static void
|
||||
on_timeout (SpaSource *source,
|
||||
void *data)
|
||||
on_timeout (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosStream *stream = data;
|
||||
add_request_clock_update (stream);
|
||||
|
|
@ -515,7 +516,8 @@ handle_rtnode_event (PinosStream *stream,
|
|||
}
|
||||
|
||||
static void
|
||||
on_rtsocket_condition (SpaSource *source,
|
||||
on_rtsocket_condition (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
|
|
|
|||
|
|
@ -57,8 +57,9 @@ post_hook (SpaLoopControl *ctrl,
|
|||
}
|
||||
|
||||
static void
|
||||
do_stop (SpaSource *source,
|
||||
void *data)
|
||||
do_stop (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosThreadMainLoopImpl *impl = data;
|
||||
impl->running = false;
|
||||
|
|
|
|||
|
|
@ -3,4 +3,4 @@ load-module libpinos-module-protocol-native
|
|||
load-module libpinos-module-suspend-on-idle
|
||||
load-module libpinos-module-spa --pattern snow
|
||||
load-module libpinos-module-autolink
|
||||
load-module libpinos-module-access
|
||||
load-module libpinos-module-flatpak
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ pinos_module_c_args = [
|
|||
'-D_GNU_SOURCE',
|
||||
]
|
||||
|
||||
pinos_module_access = shared_library('pinos-module-access', [ 'module-access.c' ],
|
||||
pinos_module_flatpak = shared_library('pinos-module-flatpak', [ 'module-flatpak.c' ],
|
||||
c_args : pinos_module_c_args,
|
||||
include_directories : [configinc, spa_inc],
|
||||
link_with : spalib,
|
||||
install : true,
|
||||
install_dir : '@0@/pinos-0.1'.format(get_option('libdir')),
|
||||
dependencies : [mathlib, dl_lib, pinos_dep, pinoscore_dep],
|
||||
dependencies : [dbus_dep, mathlib, dl_lib, pinos_dep, pinoscore_dep],
|
||||
)
|
||||
|
||||
pinos_module_autolink = shared_library('pinos-module-autolink', [ 'module-autolink.c' ],
|
||||
|
|
|
|||
|
|
@ -1,188 +0,0 @@
|
|||
/* Pinos
|
||||
* Copyright (C) 2016 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "pinos/server/core.h"
|
||||
#include "pinos/server/module.h"
|
||||
|
||||
typedef struct {
|
||||
PinosCore *core;
|
||||
PinosProperties *properties;
|
||||
|
||||
PinosListener check_send;
|
||||
PinosListener check_dispatch;
|
||||
} ModuleImpl;
|
||||
|
||||
static bool
|
||||
check_global_owner (PinosCore *core,
|
||||
PinosClient *client,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
pinos_log_debug ("%p", global);
|
||||
|
||||
if (global == NULL)
|
||||
return false;
|
||||
|
||||
pinos_log_debug ("%p", global->owner);
|
||||
|
||||
if (global->owner == NULL)
|
||||
return true;
|
||||
|
||||
pinos_log_debug ("%d %d", global->owner->ucred.uid, client->ucred.uid);
|
||||
|
||||
if (global->owner->ucred.uid == client->ucred.uid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_view_global (PinosAccess *access,
|
||||
PinosClient *client,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
if (global->type == client->core->type.link) {
|
||||
PinosLink *link = global->object;
|
||||
|
||||
pinos_log_debug ("link %p: global %p %p %p %p", link, global->owner, client, link->output, link->input);
|
||||
|
||||
/* 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;
|
||||
|
||||
pinos_log_debug ("link %p: global %p %p %p %p", link, global->owner, client, link->output, link->input);
|
||||
|
||||
if (link->input && !check_global_owner (client->core, client, link->input->node->global))
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
pinos_log_debug ("link %p: global %p %p %p %p", link, global->owner, client, link->output, link->input);
|
||||
}
|
||||
else if (!check_global_owner (client->core, client, global))
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_create_node (PinosAccess *access,
|
||||
PinosAccessData *data,
|
||||
const char *factory_name,
|
||||
const char *name,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
data->res = SPA_RESULT_OK;
|
||||
data->complete_cb (data);
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
check_timeout (SpaSource *source,
|
||||
void *d)
|
||||
{
|
||||
PinosAccessData *data = d;
|
||||
|
||||
data->res = SPA_RESULT_OK;
|
||||
data->complete_cb (data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static SpaResult
|
||||
do_create_client_node (PinosAccess *access,
|
||||
PinosAccessData *data,
|
||||
const char *name,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
#if 0
|
||||
struct timespec value;
|
||||
SpaSource *timer;
|
||||
|
||||
pinos_log_debug ("access %p: check %s %p", access, name, properties);
|
||||
|
||||
timer = pinos_loop_add_timer (data->resource->core->main_loop->loop,
|
||||
check_timeout,
|
||||
data->async_copy (data, 0));
|
||||
value.tv_sec = 3;
|
||||
value.tv_nsec = 0;
|
||||
pinos_loop_update_timer (data->resource->core->main_loop->loop,
|
||||
timer,
|
||||
&value,
|
||||
NULL,
|
||||
false);
|
||||
|
||||
return SPA_RESULT_RETURN_ASYNC (0);
|
||||
#else
|
||||
data->res = SPA_RESULT_OK;
|
||||
return SPA_RESULT_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
static PinosAccess access_checks =
|
||||
{
|
||||
do_view_global,
|
||||
do_create_node,
|
||||
do_create_client_node,
|
||||
};
|
||||
|
||||
static ModuleImpl *
|
||||
module_new (PinosCore *core,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
ModuleImpl *impl;
|
||||
|
||||
impl = calloc (1, sizeof (ModuleImpl));
|
||||
pinos_log_debug ("module %p: new", impl);
|
||||
|
||||
impl->core = core;
|
||||
impl->properties = properties;
|
||||
|
||||
core->access = &access_checks;
|
||||
|
||||
return impl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
module_destroy (ModuleImpl *impl)
|
||||
{
|
||||
pinos_log_debug ("module %p: destroy", impl);
|
||||
|
||||
pinos_global_destroy (impl->global);
|
||||
|
||||
pinos_signal_remove (&impl->global_added);
|
||||
pinos_signal_remove (&impl->global_removed);
|
||||
pinos_signal_remove (&impl->port_added);
|
||||
pinos_signal_remove (&impl->port_removed);
|
||||
pinos_signal_remove (&impl->port_unlinked);
|
||||
pinos_signal_remove (&impl->link_state_changed);
|
||||
free (impl);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
pinos__module_init (PinosModule * module, const char * args)
|
||||
{
|
||||
module_new (module->core, NULL);
|
||||
return true;
|
||||
}
|
||||
717
pinos/modules/module-flatpak.c
Normal file
717
pinos/modules/module-flatpak.c
Normal file
|
|
@ -0,0 +1,717 @@
|
|||
/* Pinos
|
||||
* Copyright (C) 2016 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 <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#include "pinos/client/utils.h"
|
||||
#include "pinos/server/core.h"
|
||||
#include "pinos/server/module.h"
|
||||
|
||||
typedef struct {
|
||||
PinosCore *core;
|
||||
PinosProperties *properties;
|
||||
|
||||
DBusConnection *bus;
|
||||
|
||||
PinosListener global_added;
|
||||
PinosListener global_removed;
|
||||
|
||||
SpaList client_list;
|
||||
PinosAccess access;
|
||||
|
||||
SpaSource *dispatch_event;
|
||||
} ModuleImpl;
|
||||
|
||||
typedef struct {
|
||||
ModuleImpl *impl;
|
||||
SpaList link;
|
||||
PinosClient *client;
|
||||
bool is_sandboxed;
|
||||
SpaList async_pending;
|
||||
} ClientInfo;
|
||||
|
||||
typedef struct {
|
||||
SpaList link;
|
||||
bool handled;
|
||||
ClientInfo *info;
|
||||
char *handle;
|
||||
PinosAccessData *access_data;
|
||||
} AsyncPending;
|
||||
|
||||
static ClientInfo *
|
||||
find_client_info (ModuleImpl *impl, PinosClient *client)
|
||||
{
|
||||
ClientInfo *info;
|
||||
|
||||
spa_list_for_each (info, &impl->client_list, link) {
|
||||
if (info->client == client)
|
||||
return info;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
close_request (AsyncPending *p)
|
||||
{
|
||||
DBusMessage *m = NULL;
|
||||
ModuleImpl *impl = p->info->impl;
|
||||
|
||||
if (!(m = dbus_message_new_method_call ("org.freedesktop.portal.Request",
|
||||
p->handle,
|
||||
"org.freedesktop.portal.Request",
|
||||
"Close"))) {
|
||||
pinos_log_error ("Failed to create message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dbus_connection_send (impl->bus, m, NULL))
|
||||
pinos_log_error ("Failed to send message");
|
||||
|
||||
dbus_message_unref(m);
|
||||
}
|
||||
|
||||
static AsyncPending *
|
||||
find_pending (ClientInfo *cinfo, const char *handle)
|
||||
{
|
||||
AsyncPending *p;
|
||||
|
||||
spa_list_for_each (p, &cinfo->async_pending, link) {
|
||||
if (strcmp (p->handle, handle) == 0)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
free_pending (PinosAccessData *d)
|
||||
{
|
||||
AsyncPending *p = d->user_data;
|
||||
|
||||
if (!p->handled)
|
||||
close_request(p);
|
||||
|
||||
spa_list_remove (&p->link);
|
||||
free (p->handle);
|
||||
}
|
||||
|
||||
static void
|
||||
add_pending (ClientInfo *cinfo, const char *handle, PinosAccessData *access_data)
|
||||
{
|
||||
AsyncPending *p;
|
||||
PinosAccessData *ad;
|
||||
|
||||
ad = access_data->async_copy (access_data, sizeof (AsyncPending));
|
||||
ad->free_cb = free_pending;
|
||||
|
||||
p = ad->user_data;
|
||||
p->info = cinfo;
|
||||
p->handle = strdup (handle);
|
||||
p->access_data = ad;
|
||||
p->handled = false;
|
||||
|
||||
spa_list_insert (cinfo->async_pending.prev, &p->link);
|
||||
}
|
||||
|
||||
static void
|
||||
client_info_free (ClientInfo *cinfo)
|
||||
{
|
||||
AsyncPending *p, *tmp;
|
||||
|
||||
spa_list_for_each_safe (p, tmp, &cinfo->async_pending, link) {
|
||||
p->access_data->res = SPA_RESULT_NO_PERMISSION;
|
||||
p->access_data->complete_cb (p->access_data);
|
||||
}
|
||||
spa_list_remove (&cinfo->link);
|
||||
free (cinfo);
|
||||
}
|
||||
|
||||
static bool
|
||||
client_is_sandboxed (PinosClient *cl)
|
||||
{
|
||||
char data[2048], *ptr;
|
||||
size_t n, size;
|
||||
const char *state = NULL;
|
||||
const char *current;
|
||||
bool result;
|
||||
int fd;
|
||||
pid_t pid;
|
||||
|
||||
if (cl->ucred_valid) {
|
||||
pinos_log_info ("client has trusted pid %d", cl->ucred.pid);
|
||||
}
|
||||
else {
|
||||
pinos_log_info ("no trusted pid found, assuming not sandboxed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
pid = cl->ucred.pid;
|
||||
|
||||
sprintf (data, "/proc/%u/cgroup", pid);
|
||||
fd = open (data, O_RDONLY | O_CLOEXEC, 0);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
|
||||
size = sizeof (data);
|
||||
ptr = data;
|
||||
|
||||
while (size > 0) {
|
||||
int r;
|
||||
|
||||
if ((r = read (fd, data, size)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
ptr += r;
|
||||
size -= r;
|
||||
}
|
||||
close (fd);
|
||||
|
||||
result = false;
|
||||
while ((current = pinos_split_walk (data, "\n", &n, &state)) != NULL) {
|
||||
if (strncmp (current, "1:name=systemd:", strlen ("1:name=systemd:")) == 0) {
|
||||
const char *p = strstr (current, "flatpak-");
|
||||
if (p && p - current < n) {
|
||||
pinos_log_info ("found a flatpak cgroup, assuming sandboxed\n");
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_global_owner (PinosCore *core,
|
||||
PinosClient *client,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
if (global == NULL)
|
||||
return false;
|
||||
|
||||
if (global->owner == NULL)
|
||||
return true;
|
||||
|
||||
if (global->owner->ucred.uid == client->ucred.uid)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_view_global (PinosAccess *access,
|
||||
PinosClient *client,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
if (global->type == client->core->type.link) {
|
||||
PinosLink *link = global->object;
|
||||
|
||||
/* 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;
|
||||
|
||||
if (link->input && !check_global_owner (client->core, client, link->input->node->global))
|
||||
return SPA_RESULT_ERROR;
|
||||
}
|
||||
else if (!check_global_owner (client->core, client, global))
|
||||
return SPA_RESULT_ERROR;
|
||||
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_create_node (PinosAccess *access,
|
||||
PinosAccessData *data,
|
||||
const char *factory_name,
|
||||
const char *name,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
ModuleImpl *impl = SPA_CONTAINER_OF (access, ModuleImpl, access);
|
||||
ClientInfo *cinfo = find_client_info (impl, data->resource->client);
|
||||
|
||||
if (cinfo->is_sandboxed)
|
||||
data->res = SPA_RESULT_NO_PERMISSION;
|
||||
else
|
||||
data->res = SPA_RESULT_OK;
|
||||
|
||||
data->complete_cb (data);
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
|
||||
static DBusHandlerResult
|
||||
portal_response (DBusConnection *connection, DBusMessage *msg, void *user_data)
|
||||
{
|
||||
ClientInfo *cinfo = user_data;
|
||||
|
||||
if (dbus_message_is_signal (msg, "org.freedesktop.portal.Request", "Response")) {
|
||||
uint32_t response = 2;
|
||||
DBusError error;
|
||||
AsyncPending *p;
|
||||
PinosAccessData *d;
|
||||
|
||||
dbus_error_init (&error);
|
||||
|
||||
dbus_connection_remove_filter (connection, portal_response, cinfo);
|
||||
|
||||
if (!dbus_message_get_args (msg, &error, DBUS_TYPE_UINT32, &response, DBUS_TYPE_INVALID)) {
|
||||
pinos_log_error("failed to parse Response: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
}
|
||||
|
||||
p = find_pending (cinfo, dbus_message_get_path (msg));
|
||||
if (p == NULL)
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
p->handled = true;
|
||||
d = p->access_data;
|
||||
|
||||
pinos_log_debug ("portal check result: %d", response);
|
||||
|
||||
d->res = response == 0 ? SPA_RESULT_OK : SPA_RESULT_NO_PERMISSION;
|
||||
d->complete_cb (d);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
static SpaResult
|
||||
do_create_client_node (PinosAccess *access,
|
||||
PinosAccessData *data,
|
||||
const char *name,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
ModuleImpl *impl = SPA_CONTAINER_OF (access, ModuleImpl, access);
|
||||
ClientInfo *cinfo = find_client_info (impl, data->resource->client);
|
||||
DBusMessage *m = NULL, *r = NULL;
|
||||
DBusError error;
|
||||
pid_t pid;
|
||||
DBusMessageIter msg_iter;
|
||||
DBusMessageIter dict_iter;
|
||||
const char *handle;
|
||||
const char *device;
|
||||
|
||||
if (!cinfo->is_sandboxed) {
|
||||
data->res = SPA_RESULT_OK;
|
||||
data->complete_cb (data);
|
||||
return SPA_RESULT_OK;
|
||||
}
|
||||
|
||||
pinos_log_info ("ask portal for client %p", cinfo->client);
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
if (!(m = dbus_message_new_method_call ("org.freedesktop.portal.Desktop",
|
||||
"/org/freedesktop/portal/desktop",
|
||||
"org.freedesktop.portal.Device",
|
||||
"AccessDevice")))
|
||||
goto no_method_call;
|
||||
|
||||
device = "camera";
|
||||
|
||||
pid = cinfo->client->ucred.pid;
|
||||
if (!dbus_message_append_args(m,
|
||||
DBUS_TYPE_UINT32, &pid,
|
||||
DBUS_TYPE_INVALID))
|
||||
goto message_failed;
|
||||
|
||||
dbus_message_iter_init_append(m, &msg_iter);
|
||||
dbus_message_iter_open_container (&msg_iter, DBUS_TYPE_ARRAY, "s", &dict_iter);
|
||||
dbus_message_iter_append_basic (&dict_iter, DBUS_TYPE_STRING, &device);
|
||||
dbus_message_iter_close_container (&msg_iter, &dict_iter);
|
||||
|
||||
dbus_message_iter_open_container (&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter);
|
||||
dbus_message_iter_close_container (&msg_iter, &dict_iter);
|
||||
|
||||
if (!(r = dbus_connection_send_with_reply_and_block (impl->bus, m, -1, &error)))
|
||||
goto send_failed;
|
||||
|
||||
dbus_message_unref(m);
|
||||
|
||||
if (!dbus_message_get_args (r, &error, DBUS_TYPE_OBJECT_PATH, &handle, DBUS_TYPE_INVALID))
|
||||
goto parse_failed;
|
||||
|
||||
dbus_message_unref (r);
|
||||
|
||||
dbus_bus_add_match (impl->bus,
|
||||
"type='signal',interface='org.freedesktop.portal.Request'",
|
||||
&error);
|
||||
dbus_connection_flush (impl->bus);
|
||||
if (dbus_error_is_set (&error))
|
||||
goto subscribe_failed;
|
||||
|
||||
dbus_connection_add_filter (impl->bus, portal_response, cinfo, NULL);
|
||||
|
||||
add_pending (cinfo, handle, data);
|
||||
|
||||
return SPA_RESULT_RETURN_ASYNC (0);
|
||||
|
||||
no_method_call:
|
||||
pinos_log_error ("Failed to create message");
|
||||
return SPA_RESULT_NO_PERMISSION;
|
||||
message_failed:
|
||||
dbus_message_unref(m);
|
||||
return SPA_RESULT_NO_PERMISSION;
|
||||
send_failed:
|
||||
pinos_log_error ("Failed to call portal: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
dbus_message_unref(m);
|
||||
return SPA_RESULT_NO_PERMISSION;
|
||||
parse_failed:
|
||||
pinos_log_error ("Failed to parse AccessDevice result: %s", error.message);
|
||||
dbus_error_free (&error);
|
||||
dbus_message_unref (r);
|
||||
return SPA_RESULT_NO_PERMISSION;
|
||||
subscribe_failed:
|
||||
pinos_log_error ("Failed to subscribe to Request signal: %s", error.message);
|
||||
dbus_error_free(&error);
|
||||
return SPA_RESULT_NO_PERMISSION;
|
||||
}
|
||||
|
||||
static PinosAccess access_checks =
|
||||
{
|
||||
do_view_global,
|
||||
do_create_node,
|
||||
do_create_client_node,
|
||||
};
|
||||
|
||||
static void
|
||||
on_global_added (PinosListener *listener,
|
||||
PinosCore *core,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
ModuleImpl *impl = SPA_CONTAINER_OF (listener, ModuleImpl, global_added);
|
||||
|
||||
if (global->type == impl->core->type.client) {
|
||||
PinosClient *client = global->object;
|
||||
ClientInfo *cinfo;
|
||||
|
||||
cinfo = calloc (1, sizeof (ClientInfo));
|
||||
cinfo->impl = impl;
|
||||
cinfo->client = client;
|
||||
cinfo->is_sandboxed = client_is_sandboxed (client);
|
||||
cinfo->is_sandboxed = true;
|
||||
spa_list_init (&cinfo->async_pending);
|
||||
|
||||
spa_list_insert (impl->client_list.prev, &cinfo->link);
|
||||
|
||||
pinos_log_debug ("module %p: client %p added", impl, client);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_global_removed (PinosListener *listener,
|
||||
PinosCore *core,
|
||||
PinosGlobal *global)
|
||||
{
|
||||
ModuleImpl *impl = SPA_CONTAINER_OF (listener, ModuleImpl, global_removed);
|
||||
|
||||
if (global->type == impl->core->type.client) {
|
||||
PinosClient *client = global->object;
|
||||
ClientInfo *cinfo;
|
||||
|
||||
if ((cinfo = find_client_info (impl, client)))
|
||||
client_info_free (cinfo);
|
||||
|
||||
pinos_log_debug ("module %p: client %p removed", impl, client);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_cb (SpaLoopUtils *utils, SpaSource *source, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
|
||||
if (dbus_connection_dispatch (impl->bus) == DBUS_DISPATCH_COMPLETE)
|
||||
pinos_loop_enable_idle (impl->core->main_loop->loop, source, false);
|
||||
}
|
||||
|
||||
static void
|
||||
dispatch_status (DBusConnection *conn, DBusDispatchStatus status, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
|
||||
pinos_loop_enable_idle (impl->core->main_loop->loop,
|
||||
impl->dispatch_event,
|
||||
status == DBUS_DISPATCH_COMPLETE ? false : true);
|
||||
}
|
||||
|
||||
static inline SpaIO
|
||||
dbus_to_io (DBusWatch *watch)
|
||||
{
|
||||
SpaIO mask;
|
||||
unsigned int flags;
|
||||
|
||||
/* no watch flags for disabled watches */
|
||||
if (!dbus_watch_get_enabled (watch))
|
||||
return 0;
|
||||
|
||||
flags = dbus_watch_get_flags (watch);
|
||||
mask = SPA_IO_HUP | SPA_IO_ERR;
|
||||
|
||||
if (flags & DBUS_WATCH_READABLE)
|
||||
mask |= SPA_IO_IN;
|
||||
if (flags & DBUS_WATCH_WRITABLE)
|
||||
mask |= SPA_IO_OUT;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
io_to_dbus (SpaIO mask)
|
||||
{
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (mask & SPA_IO_IN)
|
||||
flags |= DBUS_WATCH_READABLE;
|
||||
if (mask & SPA_IO_OUT)
|
||||
flags |= DBUS_WATCH_WRITABLE;
|
||||
if (mask & SPA_IO_HUP)
|
||||
flags |= DBUS_WATCH_HANGUP;
|
||||
if (mask & SPA_IO_ERR)
|
||||
flags |= DBUS_WATCH_ERROR;
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_io_event (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *userdata)
|
||||
{
|
||||
DBusWatch *watch = userdata;
|
||||
|
||||
if (!dbus_watch_get_enabled (watch)) {
|
||||
pinos_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
|
||||
return;
|
||||
}
|
||||
dbus_watch_handle (watch, io_to_dbus (mask));
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
add_watch (DBusWatch *watch, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
|
||||
pinos_log_debug ("add watch %p %d", watch, dbus_watch_get_unix_fd (watch));
|
||||
|
||||
/* we dup because dbus tends to add the same fd multiple times and our epoll
|
||||
* implementation does not like that */
|
||||
source = pinos_loop_add_io (impl->core->main_loop->loop,
|
||||
dup (dbus_watch_get_unix_fd (watch)),
|
||||
dbus_to_io (watch),
|
||||
true,
|
||||
handle_io_event,
|
||||
watch);
|
||||
|
||||
dbus_watch_set_data (watch, source, NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_watch (DBusWatch *watch, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
|
||||
if ((source = dbus_watch_get_data (watch)))
|
||||
pinos_loop_destroy_source (impl->core->main_loop->loop, source);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_watch (DBusWatch *watch, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
|
||||
source = dbus_watch_get_data (watch);
|
||||
|
||||
pinos_loop_update_io (impl->core->main_loop->loop,
|
||||
source,
|
||||
dbus_to_io (watch));
|
||||
}
|
||||
|
||||
static void
|
||||
handle_timer_event (SpaLoopUtils *utils, SpaSource *source, void *userdata)
|
||||
{
|
||||
DBusTimeout *timeout = userdata;
|
||||
uint64_t t;
|
||||
struct timespec ts;
|
||||
|
||||
if (dbus_timeout_get_enabled (timeout)) {
|
||||
t = dbus_timeout_get_interval (timeout) * SPA_NSEC_PER_MSEC;
|
||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||
spa_loop_utils_update_timer (utils, source, &ts, NULL, false);
|
||||
|
||||
dbus_timeout_handle (timeout);
|
||||
}
|
||||
}
|
||||
|
||||
static dbus_bool_t
|
||||
add_timeout (DBusTimeout *timeout, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
struct timespec ts;
|
||||
uint64_t t;
|
||||
|
||||
if (!dbus_timeout_get_enabled (timeout))
|
||||
return FALSE;
|
||||
|
||||
source = pinos_loop_add_timer (impl->core->main_loop->loop,
|
||||
handle_timer_event,
|
||||
timeout);
|
||||
|
||||
dbus_timeout_set_data (timeout, source, NULL);
|
||||
|
||||
t = dbus_timeout_get_interval (timeout) * SPA_NSEC_PER_MSEC;
|
||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||
pinos_loop_update_timer (impl->core->main_loop->loop,
|
||||
source,
|
||||
&ts,
|
||||
NULL,
|
||||
false);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
remove_timeout (DBusTimeout *timeout, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
|
||||
if ((source = dbus_timeout_get_data (timeout)))
|
||||
pinos_loop_destroy_source (impl->core->main_loop->loop, source);
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_timeout (DBusTimeout *timeout, void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
SpaSource *source;
|
||||
struct timespec ts, *tsp;
|
||||
|
||||
source = dbus_timeout_get_data (timeout);
|
||||
|
||||
if (dbus_timeout_get_enabled (timeout)) {
|
||||
uint64_t t = dbus_timeout_get_interval (timeout) * SPA_NSEC_PER_MSEC;
|
||||
ts.tv_sec = t / SPA_NSEC_PER_SEC;
|
||||
ts.tv_nsec = t % SPA_NSEC_PER_SEC;
|
||||
tsp = &ts;
|
||||
}
|
||||
else {
|
||||
tsp = NULL;
|
||||
}
|
||||
pinos_loop_update_timer (impl->core->main_loop->loop, source, tsp, NULL, false);
|
||||
}
|
||||
|
||||
static void
|
||||
wakeup_main (void *userdata)
|
||||
{
|
||||
ModuleImpl *impl = userdata;
|
||||
|
||||
pinos_loop_enable_idle (impl->core->main_loop->loop,
|
||||
impl->dispatch_event,
|
||||
true);
|
||||
}
|
||||
|
||||
|
||||
static ModuleImpl *
|
||||
module_new (PinosCore *core,
|
||||
PinosProperties *properties)
|
||||
{
|
||||
ModuleImpl *impl;
|
||||
DBusError error;
|
||||
|
||||
dbus_error_init(&error);
|
||||
|
||||
impl = calloc (1, sizeof (ModuleImpl));
|
||||
pinos_log_debug ("module %p: new", impl);
|
||||
|
||||
impl->core = core;
|
||||
impl->properties = properties;
|
||||
impl->access = access_checks;
|
||||
|
||||
impl->bus = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
|
||||
if (impl->bus == NULL)
|
||||
goto error;
|
||||
|
||||
impl->dispatch_event = pinos_loop_add_idle (core->main_loop->loop,
|
||||
false,
|
||||
dispatch_cb,
|
||||
impl);
|
||||
|
||||
dbus_connection_set_exit_on_disconnect (impl->bus, false);
|
||||
dbus_connection_set_dispatch_status_function (impl->bus, dispatch_status, impl, NULL);
|
||||
dbus_connection_set_watch_functions (impl->bus, add_watch, remove_watch, toggle_watch, impl, NULL);
|
||||
dbus_connection_set_timeout_functions (impl->bus, add_timeout, remove_timeout, 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);
|
||||
|
||||
pinos_signal_add (&core->global_added, &impl->global_added, on_global_added);
|
||||
pinos_signal_add (&core->global_removed, &impl->global_removed, on_global_removed);
|
||||
|
||||
return impl;
|
||||
|
||||
error:
|
||||
pinos_log_error ("Failed to connect to system bus: %s", error.message);
|
||||
dbus_error_free (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
module_destroy (ModuleImpl *impl)
|
||||
{
|
||||
pinos_log_debug ("module %p: destroy", impl);
|
||||
|
||||
dbus_connection_close (impl->bus);
|
||||
dbus_connection_unref (impl->bus);
|
||||
free (impl);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
pinos__module_init (PinosModule * module, const char * args)
|
||||
{
|
||||
module_new (module->core, NULL);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -120,10 +120,11 @@ on_before_iterate (PinosListener *listener,
|
|||
}
|
||||
|
||||
static void
|
||||
connection_data (SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
connection_data (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
{
|
||||
PinosProtocolNativeClient *client = data;
|
||||
PinosConnection *conn = client->connection;
|
||||
|
|
@ -330,10 +331,11 @@ err:
|
|||
}
|
||||
|
||||
static void
|
||||
socket_data (SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
socket_data (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data)
|
||||
{
|
||||
PinosProtocolNative *impl = data;
|
||||
PinosProtocolNativeClient *client;
|
||||
|
|
|
|||
|
|
@ -77,8 +77,9 @@ node_info_free (NodeInfo *info)
|
|||
}
|
||||
|
||||
static void
|
||||
idle_timeout (SpaSource *source,
|
||||
void *data)
|
||||
idle_timeout (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
NodeInfo *info = data;
|
||||
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ typedef struct _PinosAccessData PinosAccessData;
|
|||
struct _PinosAccessData {
|
||||
SpaResult res;
|
||||
PinosResource *resource;
|
||||
void *(*async_copy) (PinosAccessData *data, size_t size);
|
||||
void * (*async_copy) (PinosAccessData *data, size_t size);
|
||||
void (*complete_cb) (PinosAccessData *data);
|
||||
void (*free_cb) (PinosAccessData *data);
|
||||
void *user_data;
|
||||
void * user_data;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ pinos_client_new (PinosCore *core,
|
|||
this->properties = properties;
|
||||
|
||||
spa_list_init (&this->resource_list);
|
||||
pinos_signal_init (&this->properties_changed);
|
||||
pinos_signal_init (&this->resource_added);
|
||||
pinos_signal_init (&this->resource_removed);
|
||||
|
||||
|
|
@ -185,6 +186,8 @@ pinos_client_update_properties (PinosClient *client,
|
|||
client->info.change_mask = 1 << 0;
|
||||
client->info.props = client->properties ? &client->properties->dict : NULL;
|
||||
|
||||
pinos_signal_emit (&client->properties_changed, client);
|
||||
|
||||
spa_list_for_each (resource, &client->resource_list, link) {
|
||||
pinos_client_notify_info (resource, &client->info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,6 +46,9 @@ struct _PinosClient {
|
|||
PinosGlobal *global;
|
||||
|
||||
PinosProperties *properties;
|
||||
PINOS_SIGNAL (properties_changed, (PinosListener *listener,
|
||||
PinosClient *client));
|
||||
|
||||
PinosClientInfo info;
|
||||
bool ucred_valid;
|
||||
struct ucred ucred;
|
||||
|
|
|
|||
|
|
@ -111,8 +111,9 @@ do_loop (void *user_data)
|
|||
|
||||
|
||||
static void
|
||||
do_stop (SpaSource *source,
|
||||
void *data)
|
||||
do_stop (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosDataLoopImpl *impl = data;
|
||||
impl->running = false;
|
||||
|
|
|
|||
|
|
@ -48,8 +48,9 @@ typedef struct
|
|||
|
||||
|
||||
static void
|
||||
process_work_queue (SpaSource *source,
|
||||
void *data)
|
||||
process_work_queue (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data)
|
||||
{
|
||||
PinosWorkQueueImpl *impl = data;
|
||||
PinosWorkQueue *this = &impl->this;
|
||||
|
|
|
|||
|
|
@ -123,9 +123,12 @@ typedef void (*SpaNotify) (void *data);
|
|||
#define SPA_IDX_INVALID ((unsigned int)-1)
|
||||
#define SPA_ID_INVALID ((uint32_t)0xffffffff)
|
||||
|
||||
#define SPA_NSEC_PER_SEC (1000000000ll)
|
||||
#define SPA_USEC_PER_SEC (1000000ll)
|
||||
#define SPA_MSEC_PER_SEC (1000ll)
|
||||
#define SPA_NSEC_PER_SEC (1000000000ll)
|
||||
#define SPA_NSEC_PER_MSEC (1000000ll)
|
||||
#define SPA_NSEC_PER_USEC (1000ll)
|
||||
#define SPA_USEC_PER_SEC (1000000ll)
|
||||
#define SPA_USEC_PER_MSEC (1000ll)
|
||||
#define SPA_MSEC_PER_SEC (1000ll)
|
||||
|
||||
#define SPA_TIMESPEC_TO_TIME(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
|
||||
#define SPA_TIMEVAL_TO_TIME(tv) ((tv)->tv_sec * SPA_NSEC_PER_SEC + (tv)->tv_usec * 1000ll)
|
||||
|
|
|
|||
|
|
@ -126,19 +126,24 @@ struct _SpaLoopControl {
|
|||
#define spa_loop_control_leave(l) (l)->leave(l)
|
||||
|
||||
|
||||
typedef void (*SpaSourceIOFunc) (SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data);
|
||||
typedef void (*SpaSourceIdleFunc) (SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceEventFunc) (SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceTimerFunc) (SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceSignalFunc) (SpaSource *source,
|
||||
int signal_number,
|
||||
void *data);
|
||||
typedef void (*SpaSourceIOFunc) (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int fd,
|
||||
SpaIO mask,
|
||||
void *data);
|
||||
typedef void (*SpaSourceIdleFunc) (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceEventFunc) (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceTimerFunc) (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
void *data);
|
||||
typedef void (*SpaSourceSignalFunc) (SpaLoopUtils *utils,
|
||||
SpaSource *source,
|
||||
int signal_number,
|
||||
void *data);
|
||||
|
||||
/**
|
||||
* SpaLoopUtils:
|
||||
|
|
@ -160,6 +165,7 @@ struct _SpaLoopUtils {
|
|||
SpaIO mask);
|
||||
|
||||
SpaSource * (*add_idle) (SpaLoopUtils *utils,
|
||||
bool enabled,
|
||||
SpaSourceIdleFunc func,
|
||||
void *data);
|
||||
void (*enable_idle) (SpaSource *source,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue