mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05: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,7 +376,8 @@ static const PinosRegistryEvents registry_events = {
 | 
				
			||||||
typedef bool (*PinosDemarshalFunc) (void *object, void *data, size_t size);
 | 
					typedef bool (*PinosDemarshalFunc) (void *object, void *data, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
do_flush_event (SpaSource *source,
 | 
					do_flush_event (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                SpaSource    *source,
 | 
				
			||||||
                void         *data)
 | 
					                void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosContextImpl *impl = data;
 | 
					  PinosContextImpl *impl = data;
 | 
				
			||||||
| 
						 | 
					@ -394,7 +395,8 @@ on_need_flush (PinosListener   *listener,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_context_data (SpaSource *source,
 | 
					on_context_data (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                 SpaSource    *source,
 | 
				
			||||||
                 int           fd,
 | 
					                 int           fd,
 | 
				
			||||||
                 SpaIO         mask,
 | 
					                 SpaIO         mask,
 | 
				
			||||||
                 void         *data)
 | 
					                 void         *data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,21 +35,6 @@
 | 
				
			||||||
#include <pinos/client/loop.h>
 | 
					#include <pinos/client/loop.h>
 | 
				
			||||||
#include <pinos/client/log.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)
 | 
					#define DATAS_SIZE (4096 * 8)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
| 
						 | 
					@ -83,6 +68,24 @@ typedef struct {
 | 
				
			||||||
  uint8_t        buffer_data[DATAS_SIZE];
 | 
					  uint8_t        buffer_data[DATAS_SIZE];
 | 
				
			||||||
} PinosLoopImpl;
 | 
					} 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
 | 
					static inline uint32_t
 | 
				
			||||||
spa_io_to_epoll (SpaIO mask)
 | 
					spa_io_to_epoll (SpaIO mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -221,7 +224,8 @@ loop_invoke (SpaLoop       *loop,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
event_func (SpaSource *source,
 | 
					event_func (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					            SpaSource    *source,
 | 
				
			||||||
            void         *data)
 | 
					            void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosLoopImpl *impl = data;
 | 
					  PinosLoopImpl *impl = data;
 | 
				
			||||||
| 
						 | 
					@ -314,7 +318,7 @@ static void
 | 
				
			||||||
source_io_func (SpaSource *source)
 | 
					source_io_func (SpaSource *source)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, 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 *
 | 
					static SpaSource *
 | 
				
			||||||
| 
						 | 
					@ -337,6 +341,7 @@ loop_add_io (SpaLoopUtils    *utils,
 | 
				
			||||||
  source->source.data = data;
 | 
					  source->source.data = data;
 | 
				
			||||||
  source->source.fd = fd;
 | 
					  source->source.fd = fd;
 | 
				
			||||||
  source->source.mask = mask;
 | 
					  source->source.mask = mask;
 | 
				
			||||||
 | 
					  source->impl = impl;
 | 
				
			||||||
  source->close = close;
 | 
					  source->close = close;
 | 
				
			||||||
  source->func.io = func;
 | 
					  source->func.io = func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -360,11 +365,12 @@ static void
 | 
				
			||||||
source_idle_func (SpaSource *source)
 | 
					source_idle_func (SpaSource *source)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, 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 *
 | 
					static SpaSource *
 | 
				
			||||||
loop_add_idle (SpaLoopUtils      *utils,
 | 
					loop_add_idle (SpaLoopUtils      *utils,
 | 
				
			||||||
 | 
					               bool               enabled,
 | 
				
			||||||
               SpaSourceIdleFunc  func,
 | 
					               SpaSourceIdleFunc  func,
 | 
				
			||||||
               void              *data)
 | 
					               void              *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -379,6 +385,7 @@ loop_add_idle (SpaLoopUtils      *utils,
 | 
				
			||||||
  source->source.func = source_idle_func;
 | 
					  source->source.func = source_idle_func;
 | 
				
			||||||
  source->source.data = data;
 | 
					  source->source.data = data;
 | 
				
			||||||
  source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
 | 
					  source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
 | 
				
			||||||
 | 
					  source->impl = impl;
 | 
				
			||||||
  source->close = true;
 | 
					  source->close = true;
 | 
				
			||||||
  source->source.mask = SPA_IO_IN;
 | 
					  source->source.mask = SPA_IO_IN;
 | 
				
			||||||
  source->func.idle = func;
 | 
					  source->func.idle = func;
 | 
				
			||||||
| 
						 | 
					@ -387,6 +394,7 @@ loop_add_idle (SpaLoopUtils      *utils,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  spa_list_insert (&impl->source_list, &source->link);
 | 
					  spa_list_insert (&impl->source_list, &source->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (enabled)
 | 
				
			||||||
    spa_loop_utils_enable_idle (&impl->utils, &source->source, true);
 | 
					    spa_loop_utils_enable_idle (&impl->utils, &source->source, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return &source->source;
 | 
					  return &source->source;
 | 
				
			||||||
| 
						 | 
					@ -396,16 +404,18 @@ static void
 | 
				
			||||||
loop_enable_idle (SpaSource *source,
 | 
					loop_enable_idle (SpaSource *source,
 | 
				
			||||||
                  bool       enabled)
 | 
					                  bool       enabled)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  SpaSourceImpl *impl = SPA_CONTAINER_OF (source, SpaSourceImpl, source);
 | 
				
			||||||
  uint64_t count;
 | 
					  uint64_t count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (enabled) {
 | 
					  if (enabled && !impl->enabled) {
 | 
				
			||||||
    count = 1;
 | 
					    count = 1;
 | 
				
			||||||
    if (write (source->fd, &count, sizeof (uint64_t)) != sizeof (uint64_t))
 | 
					    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));
 | 
					      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))
 | 
					    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));
 | 
					      pinos_log_warn ("loop %p: failed to read idle fd: %s", source, strerror (errno));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  impl->enabled = enabled;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -417,7 +427,7 @@ source_event_func (SpaSource *source)
 | 
				
			||||||
  if (read (source->fd, &count, sizeof (uint64_t)) != sizeof (uint64_t))
 | 
					  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));
 | 
					    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 *
 | 
					static SpaSource *
 | 
				
			||||||
| 
						 | 
					@ -437,6 +447,7 @@ loop_add_event (SpaLoopUtils       *utils,
 | 
				
			||||||
  source->source.data = data;
 | 
					  source->source.data = data;
 | 
				
			||||||
  source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
 | 
					  source->source.fd = eventfd (0, EFD_CLOEXEC | EFD_NONBLOCK);
 | 
				
			||||||
  source->source.mask = SPA_IO_IN;
 | 
					  source->source.mask = SPA_IO_IN;
 | 
				
			||||||
 | 
					  source->impl = impl;
 | 
				
			||||||
  source->close = true;
 | 
					  source->close = true;
 | 
				
			||||||
  source->func.event = func;
 | 
					  source->func.event = func;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -465,7 +476,7 @@ source_timer_func (SpaSource *source)
 | 
				
			||||||
  if (read (source->fd, &expires, sizeof (uint64_t)) != sizeof (uint64_t))
 | 
					  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));
 | 
					    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 *
 | 
					static SpaSource *
 | 
				
			||||||
| 
						 | 
					@ -485,6 +496,7 @@ loop_add_timer (SpaLoopUtils       *utils,
 | 
				
			||||||
  source->source.data = data;
 | 
					  source->source.data = data;
 | 
				
			||||||
  source->source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
 | 
					  source->source.fd = timerfd_create (CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK);
 | 
				
			||||||
  source->source.mask = SPA_IO_IN;
 | 
					  source->source.mask = SPA_IO_IN;
 | 
				
			||||||
 | 
					  source->impl = impl;
 | 
				
			||||||
  source->close = true;
 | 
					  source->close = true;
 | 
				
			||||||
  source->func.timer = func;
 | 
					  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))
 | 
					  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));
 | 
					    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 *
 | 
					static SpaSource *
 | 
				
			||||||
| 
						 | 
					@ -557,6 +569,7 @@ loop_add_signal (SpaLoopUtils        *utils,
 | 
				
			||||||
  source->source.fd = signalfd (-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
 | 
					  source->source.fd = signalfd (-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
 | 
				
			||||||
  sigprocmask (SIG_BLOCK, &mask, NULL);
 | 
					  sigprocmask (SIG_BLOCK, &mask, NULL);
 | 
				
			||||||
  source->source.mask = SPA_IO_IN;
 | 
					  source->source.mask = SPA_IO_IN;
 | 
				
			||||||
 | 
					  source->impl = impl;
 | 
				
			||||||
  source->close = true;
 | 
					  source->close = true;
 | 
				
			||||||
  source->func.signal = func;
 | 
					  source->func.signal = func;
 | 
				
			||||||
  source->signal_number = signal_number;
 | 
					  source->signal_number = signal_number;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -409,7 +409,8 @@ do_node_init (PinosStream *stream)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_timeout (SpaSource *source,
 | 
					on_timeout (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					            SpaSource    *source,
 | 
				
			||||||
            void         *data)
 | 
					            void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosStream *stream = data;
 | 
					  PinosStream *stream = data;
 | 
				
			||||||
| 
						 | 
					@ -515,7 +516,8 @@ handle_rtnode_event (PinosStream  *stream,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_rtsocket_condition (SpaSource    *source,
 | 
					on_rtsocket_condition (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                       SpaSource    *source,
 | 
				
			||||||
                       int           fd,
 | 
					                       int           fd,
 | 
				
			||||||
                       SpaIO         mask,
 | 
					                       SpaIO         mask,
 | 
				
			||||||
                       void         *data)
 | 
					                       void         *data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,8 @@ post_hook (SpaLoopControl *ctrl,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
do_stop (SpaSource *source,
 | 
					do_stop (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					         SpaSource    *source,
 | 
				
			||||||
         void         *data)
 | 
					         void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosThreadMainLoopImpl *impl = data;
 | 
					  PinosThreadMainLoopImpl *impl = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,4 +3,4 @@ load-module libpinos-module-protocol-native
 | 
				
			||||||
load-module libpinos-module-suspend-on-idle
 | 
					load-module libpinos-module-suspend-on-idle
 | 
				
			||||||
load-module libpinos-module-spa --pattern snow
 | 
					load-module libpinos-module-spa --pattern snow
 | 
				
			||||||
load-module libpinos-module-autolink
 | 
					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',
 | 
					  '-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,
 | 
					  c_args : pinos_module_c_args,
 | 
				
			||||||
  include_directories : [configinc, spa_inc],
 | 
					  include_directories : [configinc, spa_inc],
 | 
				
			||||||
  link_with : spalib,
 | 
					  link_with : spalib,
 | 
				
			||||||
  install : true,
 | 
					  install : true,
 | 
				
			||||||
  install_dir : '@0@/pinos-0.1'.format(get_option('libdir')),
 | 
					  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' ],
 | 
					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,7 +120,8 @@ on_before_iterate (PinosListener *listener,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
connection_data (SpaSource *source,
 | 
					connection_data (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                 SpaSource    *source,
 | 
				
			||||||
                 int           fd,
 | 
					                 int           fd,
 | 
				
			||||||
                 SpaIO         mask,
 | 
					                 SpaIO         mask,
 | 
				
			||||||
                 void         *data)
 | 
					                 void         *data)
 | 
				
			||||||
| 
						 | 
					@ -330,7 +331,8 @@ err:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
socket_data (SpaSource *source,
 | 
					socket_data (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					             SpaSource    *source,
 | 
				
			||||||
             int           fd,
 | 
					             int           fd,
 | 
				
			||||||
             SpaIO         mask,
 | 
					             SpaIO         mask,
 | 
				
			||||||
             void         *data)
 | 
					             void         *data)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,8 @@ node_info_free (NodeInfo *info)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
idle_timeout (SpaSource *source,
 | 
					idle_timeout (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					              SpaSource    *source,
 | 
				
			||||||
              void         *data)
 | 
					              void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  NodeInfo *info = data;
 | 
					  NodeInfo *info = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,6 +102,7 @@ pinos_client_new (PinosCore       *core,
 | 
				
			||||||
  this->properties = properties;
 | 
					  this->properties = properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  spa_list_init (&this->resource_list);
 | 
					  spa_list_init (&this->resource_list);
 | 
				
			||||||
 | 
					  pinos_signal_init (&this->properties_changed);
 | 
				
			||||||
  pinos_signal_init (&this->resource_added);
 | 
					  pinos_signal_init (&this->resource_added);
 | 
				
			||||||
  pinos_signal_init (&this->resource_removed);
 | 
					  pinos_signal_init (&this->resource_removed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,6 +186,8 @@ pinos_client_update_properties (PinosClient     *client,
 | 
				
			||||||
  client->info.change_mask = 1 << 0;
 | 
					  client->info.change_mask = 1 << 0;
 | 
				
			||||||
  client->info.props = client->properties ? &client->properties->dict : NULL;
 | 
					  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) {
 | 
					  spa_list_for_each (resource, &client->resource_list, link) {
 | 
				
			||||||
    pinos_client_notify_info (resource, &client->info);
 | 
					    pinos_client_notify_info (resource, &client->info);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,9 @@ struct _PinosClient {
 | 
				
			||||||
  PinosGlobal *global;
 | 
					  PinosGlobal *global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PinosProperties *properties;
 | 
					  PinosProperties *properties;
 | 
				
			||||||
 | 
					  PINOS_SIGNAL (properties_changed, (PinosListener *listener,
 | 
				
			||||||
 | 
					                                     PinosClient   *client));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  PinosClientInfo  info;
 | 
					  PinosClientInfo  info;
 | 
				
			||||||
  bool             ucred_valid;
 | 
					  bool             ucred_valid;
 | 
				
			||||||
  struct ucred     ucred;
 | 
					  struct ucred     ucred;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -111,7 +111,8 @@ do_loop (void *user_data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
do_stop (SpaSource *source,
 | 
					do_stop (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					         SpaSource    *source,
 | 
				
			||||||
         void         *data)
 | 
					         void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosDataLoopImpl *impl = data;
 | 
					  PinosDataLoopImpl *impl = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +48,8 @@ typedef struct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
process_work_queue (SpaSource *source,
 | 
					process_work_queue (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                    SpaSource    *source,
 | 
				
			||||||
                    void         *data)
 | 
					                    void         *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  PinosWorkQueueImpl *impl = data;
 | 
					  PinosWorkQueueImpl *impl = data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,7 +124,10 @@ typedef void (*SpaNotify) (void *data);
 | 
				
			||||||
#define SPA_ID_INVALID  ((uint32_t)0xffffffff)
 | 
					#define SPA_ID_INVALID  ((uint32_t)0xffffffff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SPA_NSEC_PER_SEC  (1000000000ll)
 | 
					#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_SEC  (1000000ll)
 | 
				
			||||||
 | 
					#define SPA_USEC_PER_MSEC (1000ll)
 | 
				
			||||||
#define SPA_MSEC_PER_SEC  (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_TIMESPEC_TO_TIME(ts) ((ts)->tv_sec * SPA_NSEC_PER_SEC + (ts)->tv_nsec)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -126,17 +126,22 @@ struct _SpaLoopControl {
 | 
				
			||||||
#define spa_loop_control_leave(l)              (l)->leave(l)
 | 
					#define spa_loop_control_leave(l)              (l)->leave(l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void (*SpaSourceIOFunc)     (SpaSource *source,
 | 
					typedef void (*SpaSourceIOFunc)     (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                                     SpaSource    *source,
 | 
				
			||||||
                                     int           fd,
 | 
					                                     int           fd,
 | 
				
			||||||
                                     SpaIO         mask,
 | 
					                                     SpaIO         mask,
 | 
				
			||||||
                                     void         *data);
 | 
					                                     void         *data);
 | 
				
			||||||
typedef void (*SpaSourceIdleFunc)   (SpaSource *source,
 | 
					typedef void (*SpaSourceIdleFunc)   (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                                     SpaSource    *source,
 | 
				
			||||||
                                     void         *data);
 | 
					                                     void         *data);
 | 
				
			||||||
typedef void (*SpaSourceEventFunc)  (SpaSource *source,
 | 
					typedef void (*SpaSourceEventFunc)  (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                                     SpaSource    *source,
 | 
				
			||||||
                                     void         *data);
 | 
					                                     void         *data);
 | 
				
			||||||
typedef void (*SpaSourceTimerFunc)  (SpaSource *source,
 | 
					typedef void (*SpaSourceTimerFunc)  (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                                     SpaSource    *source,
 | 
				
			||||||
                                     void         *data);
 | 
					                                     void         *data);
 | 
				
			||||||
typedef void (*SpaSourceSignalFunc) (SpaSource *source,
 | 
					typedef void (*SpaSourceSignalFunc) (SpaLoopUtils *utils,
 | 
				
			||||||
 | 
					                                     SpaSource    *source,
 | 
				
			||||||
                                     int           signal_number,
 | 
					                                     int           signal_number,
 | 
				
			||||||
                                     void         *data);
 | 
					                                     void         *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -160,6 +165,7 @@ struct _SpaLoopUtils {
 | 
				
			||||||
                                     SpaIO               mask);
 | 
					                                     SpaIO               mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  SpaSource *  (*add_idle)          (SpaLoopUtils       *utils,
 | 
					  SpaSource *  (*add_idle)          (SpaLoopUtils       *utils,
 | 
				
			||||||
 | 
					                                     bool                enabled,
 | 
				
			||||||
                                     SpaSourceIdleFunc   func,
 | 
					                                     SpaSourceIdleFunc   func,
 | 
				
			||||||
                                     void               *data);
 | 
					                                     void               *data);
 | 
				
			||||||
  void         (*enable_idle)       (SpaSource          *source,
 | 
					  void         (*enable_idle)       (SpaSource          *source,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue