mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	Implement access control
Move send and dispatch functions to the implementation. This makes it possible to place an access check before sending and dispatching. Add module-access that allows to bind and notify on globals owned by the client.
This commit is contained in:
		
							parent
							
								
									a8964ca657
								
							
						
					
					
						commit
						ee0aa6a2ac
					
				
					 27 changed files with 819 additions and 220 deletions
				
			
		| 
						 | 
				
			
			@ -37,6 +37,9 @@ typedef struct {
 | 
			
		|||
  SpaSource source;
 | 
			
		||||
 | 
			
		||||
  bool disconnecting;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc  send_func;
 | 
			
		||||
  void          *send_data;
 | 
			
		||||
} PinosContextImpl;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -334,32 +337,40 @@ registry_dispatch_func (void             *object,
 | 
			
		|||
                                 this->uri.node);
 | 
			
		||||
        if (proxy == NULL)
 | 
			
		||||
          goto no_mem;
 | 
			
		||||
        proxy->dispatch_func = node_dispatch_func;
 | 
			
		||||
        proxy->dispatch_data = impl;
 | 
			
		||||
 | 
			
		||||
        pinos_proxy_set_dispatch (proxy,
 | 
			
		||||
                                  node_dispatch_func,
 | 
			
		||||
                                  impl);
 | 
			
		||||
      } else if (!strcmp (ng->type, PINOS_MODULE_URI)) {
 | 
			
		||||
        proxy = pinos_proxy_new (this,
 | 
			
		||||
                                 SPA_ID_INVALID,
 | 
			
		||||
                                 this->uri.module);
 | 
			
		||||
        if (proxy == NULL)
 | 
			
		||||
          goto no_mem;
 | 
			
		||||
        proxy->dispatch_func = module_dispatch_func;
 | 
			
		||||
        proxy->dispatch_data = impl;
 | 
			
		||||
 | 
			
		||||
        pinos_proxy_set_dispatch (proxy,
 | 
			
		||||
                                  module_dispatch_func,
 | 
			
		||||
                                  impl);
 | 
			
		||||
      } else if (!strcmp (ng->type, PINOS_CLIENT_URI)) {
 | 
			
		||||
        proxy = pinos_proxy_new (this,
 | 
			
		||||
                                 SPA_ID_INVALID,
 | 
			
		||||
                                 this->uri.client);
 | 
			
		||||
        if (proxy == NULL)
 | 
			
		||||
          goto no_mem;
 | 
			
		||||
        proxy->dispatch_func = client_dispatch_func;
 | 
			
		||||
        proxy->dispatch_data = impl;
 | 
			
		||||
 | 
			
		||||
        pinos_proxy_set_dispatch (proxy,
 | 
			
		||||
                                  client_dispatch_func,
 | 
			
		||||
                                  impl);
 | 
			
		||||
      } else if (!strcmp (ng->type, PINOS_LINK_URI)) {
 | 
			
		||||
        proxy = pinos_proxy_new (this,
 | 
			
		||||
                                 SPA_ID_INVALID,
 | 
			
		||||
                                 this->uri.link);
 | 
			
		||||
        if (proxy == NULL)
 | 
			
		||||
          goto no_mem;
 | 
			
		||||
        proxy->dispatch_func = link_dispatch_func;
 | 
			
		||||
        proxy->dispatch_data = impl;
 | 
			
		||||
 | 
			
		||||
        pinos_proxy_set_dispatch (proxy,
 | 
			
		||||
                                  link_dispatch_func,
 | 
			
		||||
                                  impl);
 | 
			
		||||
      }
 | 
			
		||||
      if (proxy) {
 | 
			
		||||
        PinosMessageBind m;
 | 
			
		||||
| 
						 | 
				
			
			@ -431,12 +442,8 @@ on_context_data (SpaSource *source,
 | 
			
		|||
        pinos_log_error ("context %p: could not find proxy %u", this, id);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if (proxy->dispatch_func == NULL) {
 | 
			
		||||
        pinos_log_error ("context %p: no dispatch function for proxy %u", this, id);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      proxy->dispatch_func (proxy, type, p, proxy->dispatch_data);
 | 
			
		||||
      pinos_proxy_dispatch (proxy, type, p);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -502,8 +509,9 @@ pinos_context_new (PinosLoop       *loop,
 | 
			
		|||
 | 
			
		||||
  this->state = PINOS_CONTEXT_STATE_UNCONNECTED;
 | 
			
		||||
 | 
			
		||||
  this->send_func = context_send_func;
 | 
			
		||||
  this->send_data = this;
 | 
			
		||||
  pinos_context_set_send (this,
 | 
			
		||||
                          context_send_func,
 | 
			
		||||
                          this);
 | 
			
		||||
 | 
			
		||||
  pinos_map_init (&this->objects, 64);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -621,8 +629,9 @@ pinos_context_connect (PinosContext      *context)
 | 
			
		|||
  if (context->core_proxy == NULL)
 | 
			
		||||
    goto no_proxy;
 | 
			
		||||
 | 
			
		||||
  context->core_proxy->dispatch_func = core_dispatch_func;
 | 
			
		||||
  context->core_proxy->dispatch_data = impl;
 | 
			
		||||
  pinos_proxy_set_dispatch (context->core_proxy,
 | 
			
		||||
                            core_dispatch_func,
 | 
			
		||||
                            impl);
 | 
			
		||||
 | 
			
		||||
  cu.props = &context->properties->dict;
 | 
			
		||||
  pinos_proxy_send_message (context->core_proxy,
 | 
			
		||||
| 
						 | 
				
			
			@ -636,8 +645,9 @@ pinos_context_connect (PinosContext      *context)
 | 
			
		|||
  if (context->registry_proxy == NULL)
 | 
			
		||||
    goto no_registry;
 | 
			
		||||
 | 
			
		||||
  context->registry_proxy->dispatch_func = registry_dispatch_func;
 | 
			
		||||
  context->registry_proxy->dispatch_data = impl;
 | 
			
		||||
  pinos_proxy_set_dispatch (context->registry_proxy,
 | 
			
		||||
                            registry_dispatch_func,
 | 
			
		||||
                            impl);
 | 
			
		||||
 | 
			
		||||
  grm.seq = 0;
 | 
			
		||||
  grm.new_id = context->registry_proxy->id;
 | 
			
		||||
| 
						 | 
				
			
			@ -681,6 +691,35 @@ pinos_context_disconnect (PinosContext *context)
 | 
			
		|||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_context_set_send (PinosContext  *context,
 | 
			
		||||
                        PinosSendFunc  func,
 | 
			
		||||
                        void          *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
 | 
			
		||||
 | 
			
		||||
  impl->send_func = func;
 | 
			
		||||
  impl->send_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_context_send_message (PinosContext      *context,
 | 
			
		||||
                            PinosProxy        *proxy,
 | 
			
		||||
                            uint32_t           opcode,
 | 
			
		||||
                            void              *message,
 | 
			
		||||
                            bool               flush)
 | 
			
		||||
{
 | 
			
		||||
  PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (impl->send_func)
 | 
			
		||||
    return impl->send_func (proxy, proxy->id, opcode, message, flush, impl->send_data);
 | 
			
		||||
 | 
			
		||||
  pinos_log_error ("context %p: send func not implemented", context);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_context_get_core_info (PinosContext            *context,
 | 
			
		||||
                             PinosCoreInfoCallback    cb,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,6 +33,12 @@ typedef struct _PinosContext PinosContext;
 | 
			
		|||
#include <pinos/client/proxy.h>
 | 
			
		||||
#include <pinos/client/uri.h>
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosSendFunc)     (void             *object,
 | 
			
		||||
                                        uint32_t          id,
 | 
			
		||||
                                        uint32_t          opcode,
 | 
			
		||||
                                        void             *message,
 | 
			
		||||
                                        bool              flush,
 | 
			
		||||
                                        void             *data);
 | 
			
		||||
/**
 | 
			
		||||
 * PinosContextState:
 | 
			
		||||
 * @PINOS_CONTEXT_STATE_ERROR: context is in error
 | 
			
		||||
| 
						 | 
				
			
			@ -73,9 +79,6 @@ struct _PinosContext {
 | 
			
		|||
  SpaList          stream_list;
 | 
			
		||||
  SpaList          proxy_list;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc    send_func;
 | 
			
		||||
  void            *send_data;
 | 
			
		||||
 | 
			
		||||
  PinosContextState state;
 | 
			
		||||
  char *error;
 | 
			
		||||
  PINOS_SIGNAL (state_changed,  (PinosListener *listener,
 | 
			
		||||
| 
						 | 
				
			
			@ -96,6 +99,16 @@ PinosContext *    pinos_context_new                   (PinosLoop         *loop,
 | 
			
		|||
                                                       PinosProperties   *properties);
 | 
			
		||||
void              pinos_context_destroy               (PinosContext      *context);
 | 
			
		||||
 | 
			
		||||
void              pinos_context_set_send              (PinosContext      *context,
 | 
			
		||||
                                                       PinosSendFunc      func,
 | 
			
		||||
                                                       void              *data);
 | 
			
		||||
 | 
			
		||||
SpaResult         pinos_context_send_message          (PinosContext      *context,
 | 
			
		||||
                                                       PinosProxy        *proxy,
 | 
			
		||||
                                                       uint32_t           opcode,
 | 
			
		||||
                                                       void              *message,
 | 
			
		||||
                                                       bool               flush);
 | 
			
		||||
 | 
			
		||||
bool              pinos_context_connect               (PinosContext      *context);
 | 
			
		||||
bool              pinos_context_disconnect            (PinosContext      *context);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ struct _PinosMap {
 | 
			
		|||
#define pinos_map_item_is_free(item)     ((item)->next & 0x1)
 | 
			
		||||
#define pinos_map_id_is_free(m,id)       (pinos_map_item_is_free (pinos_map_get_item(m,id)))
 | 
			
		||||
#define pinos_map_check_id(m,id)         ((id) < pinos_map_get_size (m))
 | 
			
		||||
#define pinos_map_has_item(m,id)         (pinos_map_check_id(m,id) && !pinos_map_item_is_free(m, id))
 | 
			
		||||
#define pinos_map_has_item(m,id)         (pinos_map_check_id(m,id) && !pinos_map_id_is_free(m, id))
 | 
			
		||||
#define pinos_map_lookup_unchecked(m,id) pinos_map_get_item(m,id)->data
 | 
			
		||||
 | 
			
		||||
static inline void
 | 
			
		||||
| 
						 | 
				
			
			@ -100,8 +100,11 @@ static inline void *
 | 
			
		|||
pinos_map_lookup (PinosMap *map,
 | 
			
		||||
                  uint32_t  id)
 | 
			
		||||
{
 | 
			
		||||
  if (SPA_LIKELY (pinos_map_check_id (map, id)))
 | 
			
		||||
    return pinos_map_lookup_unchecked (map, id);
 | 
			
		||||
  if (SPA_LIKELY (pinos_map_check_id (map, id))) {
 | 
			
		||||
    PinosMapItem *item = pinos_map_get_item (map, id);
 | 
			
		||||
    if (!pinos_map_item_is_free (item))
 | 
			
		||||
      return item->data;
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,8 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
typedef struct _PinosProperties PinosProperties;
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/dict.h>
 | 
			
		||||
 | 
			
		||||
struct _PinosProperties {
 | 
			
		||||
  SpaDict dict;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,9 @@
 | 
			
		|||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosProxy this;
 | 
			
		||||
 | 
			
		||||
  PinosDispatchFunc  dispatch_func;
 | 
			
		||||
  void              *dispatch_data;
 | 
			
		||||
} PinosProxyImpl;
 | 
			
		||||
 | 
			
		||||
PinosProxy *
 | 
			
		||||
| 
						 | 
				
			
			@ -40,8 +43,6 @@ pinos_proxy_new (PinosContext *context,
 | 
			
		|||
 | 
			
		||||
  this->context = context;
 | 
			
		||||
  this->type = type;
 | 
			
		||||
  this->send_func = context->send_func;
 | 
			
		||||
  this->send_data = context->send_data;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -64,16 +65,41 @@ pinos_proxy_destroy (PinosProxy *proxy)
 | 
			
		|||
  free (impl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_proxy_set_dispatch (PinosProxy        *proxy,
 | 
			
		||||
                          PinosDispatchFunc  func,
 | 
			
		||||
                          void              *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosProxyImpl *impl = SPA_CONTAINER_OF (proxy, PinosProxyImpl, this);
 | 
			
		||||
 | 
			
		||||
  impl->dispatch_func = func;
 | 
			
		||||
  impl->dispatch_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_proxy_send_message (PinosProxy        *proxy,
 | 
			
		||||
                          uint32_t           opcode,
 | 
			
		||||
                          void              *message,
 | 
			
		||||
                          bool               flush)
 | 
			
		||||
{
 | 
			
		||||
  if (proxy->send_func)
 | 
			
		||||
    return proxy->send_func (proxy, proxy->id, opcode, message, flush, proxy->send_data);
 | 
			
		||||
  return pinos_context_send_message (proxy->context,
 | 
			
		||||
                                     proxy,
 | 
			
		||||
                                     opcode,
 | 
			
		||||
                                     message,
 | 
			
		||||
                                     flush);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
  pinos_log_error ("proxy %p: send func not implemented", proxy);
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_proxy_dispatch (PinosProxy        *proxy,
 | 
			
		||||
                      uint32_t           opcode,
 | 
			
		||||
                      void              *message)
 | 
			
		||||
{
 | 
			
		||||
  PinosProxyImpl *impl = SPA_CONTAINER_OF (proxy, PinosProxyImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (impl->dispatch_func)
 | 
			
		||||
    return impl->dispatch_func (proxy, opcode, message, impl->dispatch_data);
 | 
			
		||||
 | 
			
		||||
  pinos_log_error ("proxy %p: dispatch func not implemented", proxy);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,12 +26,6 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
typedef struct _PinosProxy PinosProxy;
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosSendFunc)     (void             *object,
 | 
			
		||||
                                        uint32_t          id,
 | 
			
		||||
                                        uint32_t          opcode,
 | 
			
		||||
                                        void             *message,
 | 
			
		||||
                                        bool              flush,
 | 
			
		||||
                                        void             *data);
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosDispatchFunc) (void             *object,
 | 
			
		||||
                                        uint32_t          opcode,
 | 
			
		||||
| 
						 | 
				
			
			@ -47,12 +41,7 @@ struct _PinosProxy {
 | 
			
		|||
  uint32_t      id;
 | 
			
		||||
  uint32_t      type;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc      send_func;
 | 
			
		||||
  void              *send_data;
 | 
			
		||||
  PinosDispatchFunc  dispatch_func;
 | 
			
		||||
  void              *dispatch_data;
 | 
			
		||||
 | 
			
		||||
  void              *user_data;
 | 
			
		||||
  void         *user_data;
 | 
			
		||||
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosProxy    *proxy));
 | 
			
		||||
| 
						 | 
				
			
			@ -63,11 +52,18 @@ PinosProxy *      pinos_proxy_new                     (PinosContext      *contex
 | 
			
		|||
                                                       uint32_t           type);
 | 
			
		||||
void              pinos_proxy_destroy                 (PinosProxy        *proxy);
 | 
			
		||||
 | 
			
		||||
void              pinos_proxy_set_dispatch            (PinosProxy        *proxy,
 | 
			
		||||
                                                       PinosDispatchFunc  func,
 | 
			
		||||
                                                       void              *data);
 | 
			
		||||
 | 
			
		||||
SpaResult         pinos_proxy_send_message            (PinosProxy        *proxy,
 | 
			
		||||
                                                       uint32_t           opcode,
 | 
			
		||||
                                                       void              *message,
 | 
			
		||||
                                                       bool               flush);
 | 
			
		||||
 | 
			
		||||
SpaResult         pinos_proxy_dispatch                (PinosProxy        *proxy,
 | 
			
		||||
                                                       uint32_t           opcode,
 | 
			
		||||
                                                       void              *message);
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -868,8 +868,9 @@ pinos_stream_connect (PinosStream      *stream,
 | 
			
		|||
                                      SPA_ID_INVALID,
 | 
			
		||||
                                      0);
 | 
			
		||||
 | 
			
		||||
  impl->node_proxy->dispatch_func = stream_dispatch_func;
 | 
			
		||||
  impl->node_proxy->dispatch_data = impl;
 | 
			
		||||
  pinos_proxy_set_dispatch (impl->node_proxy,
 | 
			
		||||
                            stream_dispatch_func,
 | 
			
		||||
                            impl);
 | 
			
		||||
 | 
			
		||||
  ccn.seq = ++impl->seq;
 | 
			
		||||
  ccn.name = "client-node";
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,3 +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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,15 @@ pinos_module_c_args = [
 | 
			
		|||
  '-D_GNU_SOURCE',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
pinos_module_access = shared_library('pinos-module-access', [ 'module-access.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],
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
pinos_module_autolink = shared_library('pinos-module-autolink', [ 'module-autolink.c' ],
 | 
			
		||||
  c_args : pinos_module_c_args,
 | 
			
		||||
  include_directories : [configinc, spa_inc],
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										160
									
								
								pinos/modules/module-access.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								pinos/modules/module-access.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,160 @@
 | 
			
		|||
/* 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,
 | 
			
		||||
                    uint32_t     id)
 | 
			
		||||
{
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  global = pinos_map_lookup (&core->objects, id);
 | 
			
		||||
 | 
			
		||||
  return (global && global->owner == client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
do_check_send (PinosListener    *listener,
 | 
			
		||||
               PinosAccessFunc   func,
 | 
			
		||||
               PinosAccessData  *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosClient *client = data->client;
 | 
			
		||||
  PinosCore *core = client->core;
 | 
			
		||||
 | 
			
		||||
  if (data->resource->type == core->uri.registry) {
 | 
			
		||||
    switch (data->opcode) {
 | 
			
		||||
      case PINOS_MESSAGE_NOTIFY_GLOBAL:
 | 
			
		||||
      {
 | 
			
		||||
        PinosMessageNotifyGlobal *m = data->message;
 | 
			
		||||
 | 
			
		||||
        if (check_global_owner (core, client, m->id))
 | 
			
		||||
          data->res = SPA_RESULT_OK;
 | 
			
		||||
        else
 | 
			
		||||
          data->res = SPA_RESULT_SKIPPED;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE:
 | 
			
		||||
      {
 | 
			
		||||
        PinosMessageNotifyGlobalRemove *m = data->message;
 | 
			
		||||
 | 
			
		||||
        if (check_global_owner (core, client, m->id))
 | 
			
		||||
          data->res = SPA_RESULT_OK;
 | 
			
		||||
        else
 | 
			
		||||
          data->res = SPA_RESULT_SKIPPED;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      default:
 | 
			
		||||
        data->res = SPA_RESULT_NO_PERMISSION;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    data->res = SPA_RESULT_OK;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
do_check_dispatch (PinosListener    *listener,
 | 
			
		||||
                   PinosAccessFunc   func,
 | 
			
		||||
                   PinosAccessData  *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosClient *client = data->client;
 | 
			
		||||
  PinosCore *core = client->core;
 | 
			
		||||
 | 
			
		||||
  if (data->resource->type == core->uri.registry) {
 | 
			
		||||
    if (data->opcode == PINOS_MESSAGE_BIND) {
 | 
			
		||||
      PinosMessageBind *m = data->message;
 | 
			
		||||
 | 
			
		||||
      if (check_global_owner (core, client, m->id))
 | 
			
		||||
        data->res = SPA_RESULT_OK;
 | 
			
		||||
      else
 | 
			
		||||
        data->res = SPA_RESULT_NO_PERMISSION;
 | 
			
		||||
    } else {
 | 
			
		||||
      data->res = SPA_RESULT_NO_PERMISSION;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    data->res = SPA_RESULT_OK;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&core->access.check_send,
 | 
			
		||||
                    &impl->check_send,
 | 
			
		||||
                    do_check_send);
 | 
			
		||||
  pinos_signal_add (&core->access.check_dispatch,
 | 
			
		||||
                    &impl->check_dispatch,
 | 
			
		||||
                    do_check_dispatch);
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,6 @@ typedef struct {
 | 
			
		|||
  SpaList              link;
 | 
			
		||||
  PinosClient         *client;
 | 
			
		||||
  int                  fd;
 | 
			
		||||
  struct ucred         ucred;
 | 
			
		||||
  SpaSource           *source;
 | 
			
		||||
  PinosConnection     *connection;
 | 
			
		||||
} PinosProtocolNativeClient;
 | 
			
		||||
| 
						 | 
				
			
			@ -168,10 +167,9 @@ connection_data (SpaSource *source,
 | 
			
		|||
      continue;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    resource->dispatch_func (resource,
 | 
			
		||||
    pinos_resource_dispatch (resource,
 | 
			
		||||
                             type,
 | 
			
		||||
                             message,
 | 
			
		||||
                             resource->dispatch_data);
 | 
			
		||||
                             message);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -180,14 +178,14 @@ client_new (PinosProtocolNative *impl,
 | 
			
		|||
            int                  fd)
 | 
			
		||||
{
 | 
			
		||||
  PinosProtocolNativeClient *this;
 | 
			
		||||
  PinosClient *client;
 | 
			
		||||
  socklen_t len;
 | 
			
		||||
 | 
			
		||||
  this = calloc (1, sizeof (PinosProtocolNativeClient));
 | 
			
		||||
  if (this == NULL)
 | 
			
		||||
    goto no_native_client;
 | 
			
		||||
 | 
			
		||||
  this->impl = impl;
 | 
			
		||||
  len = sizeof (this->ucred);
 | 
			
		||||
  if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &this->ucred, &len) < 0) {
 | 
			
		||||
    pinos_log_error ("no peercred: %m");
 | 
			
		||||
  }
 | 
			
		||||
  this->fd = fd;
 | 
			
		||||
  this->source = pinos_loop_add_io (impl->core->main_loop->loop,
 | 
			
		||||
                                    this->fd,
 | 
			
		||||
| 
						 | 
				
			
			@ -195,21 +193,48 @@ client_new (PinosProtocolNative *impl,
 | 
			
		|||
                                    false,
 | 
			
		||||
                                    connection_data,
 | 
			
		||||
                                    this);
 | 
			
		||||
  if (this->source == NULL)
 | 
			
		||||
    goto no_source;
 | 
			
		||||
 | 
			
		||||
  this->connection = pinos_connection_new (fd);
 | 
			
		||||
  if (this->connection == NULL)
 | 
			
		||||
    goto no_connection;
 | 
			
		||||
 | 
			
		||||
  client = pinos_client_new (impl->core, NULL);
 | 
			
		||||
  if (client == NULL)
 | 
			
		||||
    goto no_client;
 | 
			
		||||
 | 
			
		||||
  this->client = client;
 | 
			
		||||
 | 
			
		||||
  pinos_client_set_send (client,
 | 
			
		||||
                         client_send_func,
 | 
			
		||||
                         this);
 | 
			
		||||
 | 
			
		||||
  len = sizeof (client->ucred);
 | 
			
		||||
  if (getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &client->ucred, &len) < 0) {
 | 
			
		||||
    client->ucred_valid = false;
 | 
			
		||||
    pinos_log_error ("no peercred: %m");
 | 
			
		||||
  } else {
 | 
			
		||||
    client->ucred_valid = true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  spa_list_insert (impl->client_list.prev, &this->link);
 | 
			
		||||
 | 
			
		||||
  this->client = pinos_client_new (impl->core, NULL);
 | 
			
		||||
  this->client->send_func = client_send_func;
 | 
			
		||||
  this->client->send_data = this;
 | 
			
		||||
 | 
			
		||||
  impl->core->global->bind (impl->core->global,
 | 
			
		||||
                            this->client,
 | 
			
		||||
                            0,
 | 
			
		||||
                            0);
 | 
			
		||||
 | 
			
		||||
  pinos_global_bind (impl->core->global,
 | 
			
		||||
                     client,
 | 
			
		||||
                     0,
 | 
			
		||||
                     0);
 | 
			
		||||
  return this;
 | 
			
		||||
 | 
			
		||||
no_client:
 | 
			
		||||
  pinos_connection_destroy (this->connection);
 | 
			
		||||
no_connection:
 | 
			
		||||
  pinos_loop_destroy_source (impl->core->main_loop->loop,
 | 
			
		||||
                             this->source);
 | 
			
		||||
no_source:
 | 
			
		||||
  free (this);
 | 
			
		||||
no_native_client:
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Socket *
 | 
			
		||||
| 
						 | 
				
			
			@ -326,7 +351,11 @@ socket_data (SpaSource *source,
 | 
			
		|||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  client_new (impl, client_fd);
 | 
			
		||||
  if (client_new (impl, client_fd) == NULL) {
 | 
			
		||||
    pinos_log_error ("failed to create client");
 | 
			
		||||
    close (client_fd);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										27
									
								
								pinos/server/access.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								pinos/server/access.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/* Pinos
 | 
			
		||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Library General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Library General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Library General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "pinos/server/core.h"
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_access_init (PinosAccess *access)
 | 
			
		||||
{
 | 
			
		||||
  pinos_signal_init (&access->check_send);
 | 
			
		||||
  pinos_signal_init (&access->check_dispatch);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								pinos/server/access.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								pinos/server/access.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
/* Pinos
 | 
			
		||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This library is free software; you can redistribute it and/or
 | 
			
		||||
 * modify it under the terms of the GNU Library General Public
 | 
			
		||||
 * License as published by the Free Software Foundation; either
 | 
			
		||||
 * version 2 of the License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This library is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * Library General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Library General Public
 | 
			
		||||
 * License along with this library; if not, write to the
 | 
			
		||||
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 | 
			
		||||
 * Boston, MA 02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __PINOS_ACCESS_H__
 | 
			
		||||
#define __PINOS_ACCESS_H__
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define PINOS_ACCESS_URI                            "http://pinos.org/ns/access"
 | 
			
		||||
#define PINOS_ACCESS_PREFIX                         PINOS_ACCESS_URI "#"
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/sig.h>
 | 
			
		||||
 | 
			
		||||
typedef struct _PinosAccess PinosAccess;
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/client.h>
 | 
			
		||||
#include <pinos/server/resource.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  SpaResult         res;
 | 
			
		||||
  PinosClient      *client;
 | 
			
		||||
  PinosResource    *resource;
 | 
			
		||||
  uint32_t          opcode;
 | 
			
		||||
  void             *message;
 | 
			
		||||
  bool              flush;
 | 
			
		||||
} PinosAccessData;
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosAccessFunc) (PinosAccessData *data);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PinosAccess:
 | 
			
		||||
 *
 | 
			
		||||
 * Pinos Access support struct.
 | 
			
		||||
 */
 | 
			
		||||
struct _PinosAccess {
 | 
			
		||||
  PINOS_SIGNAL (check_send,     (PinosListener    *listener,
 | 
			
		||||
                                 PinosAccessFunc   func,
 | 
			
		||||
                                 PinosAccessData  *data));
 | 
			
		||||
  PINOS_SIGNAL (check_dispatch, (PinosListener    *listener,
 | 
			
		||||
                                 PinosAccessFunc   func,
 | 
			
		||||
                                 PinosAccessData  *data));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void pinos_access_init (PinosAccess *access);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __PINOS_ACCESS_H__ */
 | 
			
		||||
| 
						 | 
				
			
			@ -121,6 +121,7 @@ typedef struct
 | 
			
		|||
 | 
			
		||||
  PinosListener transport_changed;
 | 
			
		||||
  PinosListener loop_changed;
 | 
			
		||||
  PinosListener global_added;
 | 
			
		||||
 | 
			
		||||
  int data_fd;
 | 
			
		||||
} PinosClientNodeImpl;
 | 
			
		||||
| 
						 | 
				
			
			@ -1187,6 +1188,16 @@ on_loop_changed (PinosListener   *listener,
 | 
			
		|||
  impl->proxy.data_loop = node->data_loop->loop->loop;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_global_added (PinosListener   *listener,
 | 
			
		||||
                 PinosCore       *core,
 | 
			
		||||
                 PinosGlobal     *global)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientNodeImpl *impl = SPA_CONTAINER_OF (listener, PinosClientNodeImpl, global_added);
 | 
			
		||||
  if (global->object == impl->this.node)
 | 
			
		||||
    global->owner = impl->this.client;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpaResult
 | 
			
		||||
proxy_clear (SpaProxy *this)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1256,14 +1267,6 @@ pinos_client_node_new (PinosClient     *client,
 | 
			
		|||
 | 
			
		||||
  impl->proxy.pnode = this->node;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&this->node->transport_changed,
 | 
			
		||||
                    &impl->transport_changed,
 | 
			
		||||
                    on_transport_changed);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&this->node->loop_changed,
 | 
			
		||||
                    &impl->loop_changed,
 | 
			
		||||
                    on_loop_changed);
 | 
			
		||||
 | 
			
		||||
  this->resource = pinos_resource_new (client,
 | 
			
		||||
                                       id,
 | 
			
		||||
                                       client->core->uri.client_node,
 | 
			
		||||
| 
						 | 
				
			
			@ -1273,8 +1276,22 @@ pinos_client_node_new (PinosClient     *client,
 | 
			
		|||
    goto error_no_resource;
 | 
			
		||||
 | 
			
		||||
  impl->proxy.resource = this->resource;
 | 
			
		||||
  this->resource->dispatch_func = client_node_dispatch_func;
 | 
			
		||||
  this->resource->dispatch_data = this;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&this->node->transport_changed,
 | 
			
		||||
                    &impl->transport_changed,
 | 
			
		||||
                    on_transport_changed);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&this->node->loop_changed,
 | 
			
		||||
                    &impl->loop_changed,
 | 
			
		||||
                    on_loop_changed);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_add (&impl->core->global_added,
 | 
			
		||||
                    &impl->global_added,
 | 
			
		||||
                    on_global_added);
 | 
			
		||||
 | 
			
		||||
  pinos_resource_set_dispatch (this->resource,
 | 
			
		||||
                               client_node_dispatch_func,
 | 
			
		||||
                               this);
 | 
			
		||||
 | 
			
		||||
  return this;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1312,6 +1329,8 @@ pinos_client_node_destroy (PinosClientNode * this)
 | 
			
		|||
  pinos_log_debug ("client-node %p: destroy", impl);
 | 
			
		||||
  pinos_signal_emit (&this->destroy_signal, this);
 | 
			
		||||
 | 
			
		||||
  pinos_signal_remove (&impl->global_added);
 | 
			
		||||
 | 
			
		||||
  pinos_node_destroy (this->node);
 | 
			
		||||
 | 
			
		||||
  pinos_main_loop_defer (this->node->core->main_loop,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,9 @@
 | 
			
		|||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
  PinosClient this;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc   send_func;
 | 
			
		||||
  void           *send_data;
 | 
			
		||||
} PinosClientImpl;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +56,7 @@ client_unbind_func (void *data)
 | 
			
		|||
  spa_list_remove (&resource->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static SpaResult
 | 
			
		||||
client_bind_func (PinosGlobal *global,
 | 
			
		||||
                  PinosClient *client,
 | 
			
		||||
                  uint32_t     version,
 | 
			
		||||
| 
						 | 
				
			
			@ -66,14 +69,15 @@ client_bind_func (PinosGlobal *global,
 | 
			
		|||
 | 
			
		||||
  resource = pinos_resource_new (client,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 global->core->uri.client,
 | 
			
		||||
                                 global->type,
 | 
			
		||||
                                 global->object,
 | 
			
		||||
                                 client_unbind_func);
 | 
			
		||||
  if (resource == NULL)
 | 
			
		||||
    goto no_mem;
 | 
			
		||||
 | 
			
		||||
  resource->dispatch_func = client_dispatch_func;
 | 
			
		||||
  resource->dispatch_data = global;
 | 
			
		||||
  pinos_resource_set_dispatch (resource,
 | 
			
		||||
                               client_dispatch_func,
 | 
			
		||||
                               global);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("client %p: bound to %d", global->object, resource->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,16 +88,15 @@ client_bind_func (PinosGlobal *global,
 | 
			
		|||
  info.change_mask = ~0;
 | 
			
		||||
  info.props = this->properties ? &this->properties->dict : NULL;
 | 
			
		||||
 | 
			
		||||
  pinos_resource_send_message (resource,
 | 
			
		||||
                               PINOS_MESSAGE_CLIENT_INFO,
 | 
			
		||||
                               &m,
 | 
			
		||||
                               true);
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
  return pinos_resource_send_message (resource,
 | 
			
		||||
                                      PINOS_MESSAGE_CLIENT_INFO,
 | 
			
		||||
                                      &m,
 | 
			
		||||
                                      true);
 | 
			
		||||
no_mem:
 | 
			
		||||
  pinos_resource_send_error (client->core_resource,
 | 
			
		||||
                             SPA_RESULT_NO_MEMORY,
 | 
			
		||||
                             "no memory");
 | 
			
		||||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +133,7 @@ pinos_client_new (PinosCore       *core,
 | 
			
		|||
  spa_list_insert (core->client_list.prev, &this->link);
 | 
			
		||||
 | 
			
		||||
  this->global = pinos_core_add_global (core,
 | 
			
		||||
                                        this,
 | 
			
		||||
                                        core->uri.client,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this,
 | 
			
		||||
| 
						 | 
				
			
			@ -191,6 +195,78 @@ pinos_client_destroy (PinosClient * client)
 | 
			
		|||
                         client);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_client_set_send (PinosClient     *client,
 | 
			
		||||
                       PinosSendFunc    func,
 | 
			
		||||
                       void            *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
 | 
			
		||||
 | 
			
		||||
  impl->send_func = func;
 | 
			
		||||
  impl->send_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpaResult
 | 
			
		||||
do_send_message (PinosAccessData *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (data->client, PinosClientImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (data->res == SPA_RESULT_SKIPPED) {
 | 
			
		||||
    data->res = SPA_RESULT_OK;
 | 
			
		||||
  } else if (data->res == SPA_RESULT_NO_PERMISSION) {
 | 
			
		||||
    pinos_resource_send_error (data->resource,
 | 
			
		||||
                               data->res,
 | 
			
		||||
                               "no permission");
 | 
			
		||||
  } else if (SPA_RESULT_IS_ERROR (data->res)) {
 | 
			
		||||
    pinos_resource_send_error (data->resource,
 | 
			
		||||
                               data->res,
 | 
			
		||||
                               "error %d", data->res);
 | 
			
		||||
  } else {
 | 
			
		||||
    data->res = impl->send_func (data->resource,
 | 
			
		||||
                                 data->resource->id,
 | 
			
		||||
                                 data->opcode,
 | 
			
		||||
                                 data->message,
 | 
			
		||||
                                 data->flush,
 | 
			
		||||
                                 impl->send_data);
 | 
			
		||||
  }
 | 
			
		||||
  return data->res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_client_send_message (PinosClient   *client,
 | 
			
		||||
                           PinosResource *resource,
 | 
			
		||||
                           uint32_t       opcode,
 | 
			
		||||
                           void          *message,
 | 
			
		||||
                           bool           flush)
 | 
			
		||||
{
 | 
			
		||||
  PinosClientImpl *impl = SPA_CONTAINER_OF (client, PinosClientImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (impl->send_func) {
 | 
			
		||||
    PinosAccessData data;
 | 
			
		||||
 | 
			
		||||
    data.client = client;
 | 
			
		||||
    data.resource = resource;
 | 
			
		||||
    data.opcode = opcode;
 | 
			
		||||
    data.message = message;
 | 
			
		||||
    data.flush = flush;
 | 
			
		||||
 | 
			
		||||
    data.res = SPA_RESULT_OK;
 | 
			
		||||
    pinos_signal_emit (&client->core->access.check_send,
 | 
			
		||||
                       do_send_message,
 | 
			
		||||
                       &data);
 | 
			
		||||
 | 
			
		||||
    if (SPA_RESULT_IS_ASYNC (data.res))
 | 
			
		||||
      return data.res;
 | 
			
		||||
 | 
			
		||||
    return do_send_message (&data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pinos_log_error ("client %p: send func not implemented", client);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_client_update_properties (PinosClient     *client,
 | 
			
		||||
                                const SpaDict   *dict)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,9 +26,21 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
typedef struct _PinosClient PinosClient;
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/properties.h>
 | 
			
		||||
#include <pinos/client/sig.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/core.h>
 | 
			
		||||
#include <pinos/server/resource.h>
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosSendFunc) (void             *object,
 | 
			
		||||
                                    uint32_t          id,
 | 
			
		||||
                                    uint32_t          opcode,
 | 
			
		||||
                                    void             *message,
 | 
			
		||||
                                    bool              flush,
 | 
			
		||||
                                    void             *data);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * PinosClient:
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +52,8 @@ struct _PinosClient {
 | 
			
		|||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  PinosProperties *properties;
 | 
			
		||||
  bool             ucred_valid;
 | 
			
		||||
  struct ucred     ucred;
 | 
			
		||||
 | 
			
		||||
  PinosResource *core_resource;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -47,9 +61,6 @@ struct _PinosClient {
 | 
			
		|||
 | 
			
		||||
  SpaList resource_list;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc   send_func;
 | 
			
		||||
  void           *send_data;
 | 
			
		||||
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosClient *client));
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -57,6 +68,17 @@ struct _PinosClient {
 | 
			
		|||
PinosClient *   pinos_client_new                  (PinosCore       *core,
 | 
			
		||||
                                                   PinosProperties *properties);
 | 
			
		||||
void            pinos_client_destroy              (PinosClient     *client);
 | 
			
		||||
 | 
			
		||||
void            pinos_client_set_send             (PinosClient     *client,
 | 
			
		||||
                                                   PinosSendFunc    func,
 | 
			
		||||
                                                   void            *data);
 | 
			
		||||
 | 
			
		||||
SpaResult       pinos_client_send_message         (PinosClient     *client,
 | 
			
		||||
                                                   PinosResource   *resource,
 | 
			
		||||
                                                   uint32_t         opcode,
 | 
			
		||||
                                                   void            *message,
 | 
			
		||||
                                                   bool             flush);
 | 
			
		||||
 | 
			
		||||
void            pinos_client_update_properties    (PinosClient     *client,
 | 
			
		||||
                                                   const SpaDict   *dict);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,6 +23,11 @@
 | 
			
		|||
#include <pinos/server/data-loop.h>
 | 
			
		||||
#include <pinos/server/client-node.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosGlobal   this;
 | 
			
		||||
  PinosBindFunc bind;
 | 
			
		||||
} PinosGlobalImpl;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosCore  this;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +41,7 @@ registry_dispatch_func (void             *object,
 | 
			
		|||
                        void             *message,
 | 
			
		||||
                        void             *data)
 | 
			
		||||
{
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
  PinosResource *resource = object;
 | 
			
		||||
  PinosClient *client = resource->client;
 | 
			
		||||
  PinosCore *this = data;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,22 +62,16 @@ registry_dispatch_func (void             *object,
 | 
			
		|||
                                   "unknown object id %u", m->id);
 | 
			
		||||
        return SPA_RESULT_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
      if (global->bind == NULL) {
 | 
			
		||||
        pinos_resource_send_error (resource,
 | 
			
		||||
                                   SPA_RESULT_NOT_IMPLEMENTED,
 | 
			
		||||
                                   "can't bind object id %d", m->id);
 | 
			
		||||
        return SPA_RESULT_ERROR;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      pinos_log_debug ("global %p: bind object id %d", global, m->id);
 | 
			
		||||
      global->bind (global, client, 0, m->id);
 | 
			
		||||
      res = pinos_global_bind (global, client, 0, m->id);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    default:
 | 
			
		||||
      pinos_log_error ("unhandled message %d", type);
 | 
			
		||||
      res = SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
  return SPA_RESULT_OK;
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -116,8 +116,9 @@ core_dispatch_func (void             *object,
 | 
			
		|||
      if (registry_resource == NULL)
 | 
			
		||||
        goto no_mem;
 | 
			
		||||
 | 
			
		||||
      registry_resource->dispatch_func = registry_dispatch_func;
 | 
			
		||||
      registry_resource->dispatch_data = this;
 | 
			
		||||
      pinos_resource_set_dispatch (registry_resource,
 | 
			
		||||
                                   registry_dispatch_func,
 | 
			
		||||
                                   this);
 | 
			
		||||
 | 
			
		||||
      spa_list_insert (this->registry_resource_list.prev, ®istry_resource->link);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +192,7 @@ no_mem:
 | 
			
		|||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static SpaResult
 | 
			
		||||
core_bind_func (PinosGlobal *global,
 | 
			
		||||
                PinosClient *client,
 | 
			
		||||
                uint32_t     version,
 | 
			
		||||
| 
						 | 
				
			
			@ -204,14 +205,15 @@ core_bind_func (PinosGlobal *global,
 | 
			
		|||
 | 
			
		||||
  resource = pinos_resource_new (client,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 global->core->uri.core,
 | 
			
		||||
                                 global->type,
 | 
			
		||||
                                 global->object,
 | 
			
		||||
                                 NULL);
 | 
			
		||||
  if (resource == NULL)
 | 
			
		||||
    goto no_mem;
 | 
			
		||||
 | 
			
		||||
  resource->dispatch_func = core_dispatch_func;
 | 
			
		||||
  resource->dispatch_data = this;
 | 
			
		||||
  pinos_resource_set_dispatch (resource,
 | 
			
		||||
                               core_dispatch_func,
 | 
			
		||||
                               this);
 | 
			
		||||
 | 
			
		||||
  client->core_resource = resource;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -228,14 +230,13 @@ core_bind_func (PinosGlobal *global,
 | 
			
		|||
  info.cookie = random ();
 | 
			
		||||
  info.props = NULL;
 | 
			
		||||
 | 
			
		||||
  pinos_resource_send_message (resource,
 | 
			
		||||
                               PINOS_MESSAGE_CORE_INFO,
 | 
			
		||||
                               &m,
 | 
			
		||||
                               true);
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
  return pinos_resource_send_message (resource,
 | 
			
		||||
                                      PINOS_MESSAGE_CORE_INFO,
 | 
			
		||||
                                      &m,
 | 
			
		||||
                                      true);
 | 
			
		||||
no_mem:
 | 
			
		||||
  pinos_log_error ("can't create core resource");
 | 
			
		||||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosCore *
 | 
			
		||||
| 
						 | 
				
			
			@ -256,6 +257,7 @@ pinos_core_new (PinosMainLoop *main_loop)
 | 
			
		|||
  this->main_loop = main_loop;
 | 
			
		||||
 | 
			
		||||
  pinos_uri_init (&this->uri);
 | 
			
		||||
  pinos_access_init (&this->access);
 | 
			
		||||
  pinos_map_init (&this->objects, 512);
 | 
			
		||||
 | 
			
		||||
  impl->support[0].uri = SPA_ID_MAP_URI;
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +292,7 @@ pinos_core_new (PinosMainLoop *main_loop)
 | 
			
		|||
  pinos_signal_init (&this->node_unlink_done);
 | 
			
		||||
 | 
			
		||||
  this->global = pinos_core_add_global (this,
 | 
			
		||||
                                        NULL,
 | 
			
		||||
                                        this->uri.core,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this,
 | 
			
		||||
| 
						 | 
				
			
			@ -315,44 +318,70 @@ pinos_core_destroy (PinosCore *core)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
PinosGlobal *
 | 
			
		||||
pinos_core_add_global (PinosCore           *core,
 | 
			
		||||
                       uint32_t             type,
 | 
			
		||||
                       uint32_t             version,
 | 
			
		||||
                       void                *object,
 | 
			
		||||
                       PinosBindFunc        bind)
 | 
			
		||||
pinos_core_add_global (PinosCore     *core,
 | 
			
		||||
                       PinosClient   *owner,
 | 
			
		||||
                       uint32_t       type,
 | 
			
		||||
                       uint32_t       version,
 | 
			
		||||
                       void          *object,
 | 
			
		||||
                       PinosBindFunc  bind)
 | 
			
		||||
{
 | 
			
		||||
  PinosGlobal *global;
 | 
			
		||||
  PinosGlobalImpl *impl;
 | 
			
		||||
  PinosGlobal *this;
 | 
			
		||||
  PinosResource *registry;
 | 
			
		||||
  PinosMessageNotifyGlobal ng;
 | 
			
		||||
 | 
			
		||||
  global = calloc (1, sizeof (PinosGlobal));
 | 
			
		||||
  if (global == NULL)
 | 
			
		||||
  impl = calloc (1, sizeof (PinosGlobalImpl));
 | 
			
		||||
  if (impl == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  global->core = core;
 | 
			
		||||
  global->type = type;
 | 
			
		||||
  global->version = version;
 | 
			
		||||
  global->object = object;
 | 
			
		||||
  global->bind = bind;
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
  impl->bind = bind;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&global->destroy_signal);
 | 
			
		||||
  this->core = core;
 | 
			
		||||
  this->owner = owner;
 | 
			
		||||
  this->type = type;
 | 
			
		||||
  this->version = version;
 | 
			
		||||
  this->object = object;
 | 
			
		||||
 | 
			
		||||
  global->id = pinos_map_insert_new (&core->objects, global);
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  spa_list_insert (core->global_list.prev, &global->link);
 | 
			
		||||
  pinos_signal_emit (&core->global_added, core, global);
 | 
			
		||||
  this->id = pinos_map_insert_new (&core->objects, this);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("global %p: new %u", global, global->id);
 | 
			
		||||
  spa_list_insert (core->global_list.prev, &this->link);
 | 
			
		||||
  pinos_signal_emit (&core->global_added, core, this);
 | 
			
		||||
 | 
			
		||||
  ng.id = global->id;
 | 
			
		||||
  ng.type = spa_id_map_get_uri (core->uri.map, global->type);
 | 
			
		||||
  pinos_log_debug ("global %p: new %u", this, this->id);
 | 
			
		||||
 | 
			
		||||
  ng.id = this->id;
 | 
			
		||||
  ng.type = spa_id_map_get_uri (core->uri.map, this->type);
 | 
			
		||||
  spa_list_for_each (registry, &core->registry_resource_list, link) {
 | 
			
		||||
    pinos_resource_send_message (registry,
 | 
			
		||||
                                 PINOS_MESSAGE_NOTIFY_GLOBAL,
 | 
			
		||||
                                 &ng,
 | 
			
		||||
                                 true);
 | 
			
		||||
  }
 | 
			
		||||
  return global;
 | 
			
		||||
  return this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_global_bind (PinosGlobal   *global,
 | 
			
		||||
                   PinosClient   *client,
 | 
			
		||||
                   uint32_t       version,
 | 
			
		||||
                   uint32_t       id)
 | 
			
		||||
{
 | 
			
		||||
  SpaResult res;
 | 
			
		||||
  PinosGlobalImpl *impl = SPA_CONTAINER_OF (global, PinosGlobalImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (impl->bind) {
 | 
			
		||||
 | 
			
		||||
    res = impl->bind (global, client, version, id);
 | 
			
		||||
  } else {
 | 
			
		||||
    res = SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
    pinos_resource_send_error (client->core_resource,
 | 
			
		||||
                               res,
 | 
			
		||||
                               "can't bind object id %d", id);
 | 
			
		||||
  }
 | 
			
		||||
  return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,26 +31,26 @@ typedef struct _PinosGlobal PinosGlobal;
 | 
			
		|||
 | 
			
		||||
#include <pinos/client/uri.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/access.h>
 | 
			
		||||
#include <pinos/server/main-loop.h>
 | 
			
		||||
#include <pinos/server/data-loop.h>
 | 
			
		||||
#include <pinos/server/node.h>
 | 
			
		||||
#include <pinos/server/link.h>
 | 
			
		||||
#include <pinos/server/node-factory.h>
 | 
			
		||||
 | 
			
		||||
typedef void (*PinosBindFunc)  (PinosGlobal   *global,
 | 
			
		||||
                                PinosClient   *client,
 | 
			
		||||
                                uint32_t       version,
 | 
			
		||||
                                uint32_t       id);
 | 
			
		||||
typedef SpaResult (*PinosBindFunc)  (PinosGlobal   *global,
 | 
			
		||||
                                     PinosClient   *client,
 | 
			
		||||
                                     uint32_t       version,
 | 
			
		||||
                                     uint32_t       id);
 | 
			
		||||
 | 
			
		||||
struct _PinosGlobal {
 | 
			
		||||
  PinosCore *core;
 | 
			
		||||
  SpaList    link;
 | 
			
		||||
  uint32_t   id;
 | 
			
		||||
  uint32_t   type;
 | 
			
		||||
  uint32_t   version;
 | 
			
		||||
  void      *object;
 | 
			
		||||
 | 
			
		||||
  PinosBindFunc bind;
 | 
			
		||||
  PinosCore   *core;
 | 
			
		||||
  PinosClient *owner;
 | 
			
		||||
  SpaList      link;
 | 
			
		||||
  uint32_t     id;
 | 
			
		||||
  uint32_t     type;
 | 
			
		||||
  uint32_t     version;
 | 
			
		||||
  void        *object;
 | 
			
		||||
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosGlobal   *global));
 | 
			
		||||
| 
						 | 
				
			
			@ -65,6 +65,7 @@ struct _PinosCore {
 | 
			
		|||
  PinosGlobal *global;
 | 
			
		||||
 | 
			
		||||
  PinosURI uri;
 | 
			
		||||
  PinosAccess access;
 | 
			
		||||
 | 
			
		||||
  PinosMap objects;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -119,12 +120,18 @@ struct _PinosCore {
 | 
			
		|||
PinosCore *     pinos_core_new           (PinosMainLoop *main_loop);
 | 
			
		||||
void            pinos_core_destroy       (PinosCore     *core);
 | 
			
		||||
 | 
			
		||||
PinosGlobal *   pinos_core_add_global    (PinosCore           *core,
 | 
			
		||||
                                          uint32_t             type,
 | 
			
		||||
                                          uint32_t             version,
 | 
			
		||||
                                          void                *object,
 | 
			
		||||
                                          PinosBindFunc        bind);
 | 
			
		||||
void            pinos_global_destroy     (PinosGlobal         *global);
 | 
			
		||||
PinosGlobal *   pinos_core_add_global    (PinosCore     *core,
 | 
			
		||||
                                          PinosClient   *owner,
 | 
			
		||||
                                          uint32_t       type,
 | 
			
		||||
                                          uint32_t       version,
 | 
			
		||||
                                          void          *object,
 | 
			
		||||
                                          PinosBindFunc  bind);
 | 
			
		||||
 | 
			
		||||
SpaResult       pinos_global_bind        (PinosGlobal   *global,
 | 
			
		||||
                                          PinosClient   *client,
 | 
			
		||||
                                          uint32_t       version,
 | 
			
		||||
                                          uint32_t       id);
 | 
			
		||||
void            pinos_global_destroy     (PinosGlobal   *global);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
PinosPort *     pinos_core_find_port     (PinosCore        *core,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -756,7 +756,7 @@ link_unbind_func (void *data)
 | 
			
		|||
  spa_list_remove (&resource->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static SpaResult
 | 
			
		||||
link_bind_func (PinosGlobal *global,
 | 
			
		||||
                PinosClient *client,
 | 
			
		||||
                uint32_t     version,
 | 
			
		||||
| 
						 | 
				
			
			@ -769,14 +769,15 @@ link_bind_func (PinosGlobal *global,
 | 
			
		|||
 | 
			
		||||
  resource = pinos_resource_new (client,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 global->core->uri.link,
 | 
			
		||||
                                 global->type,
 | 
			
		||||
                                 global->object,
 | 
			
		||||
                                 link_unbind_func);
 | 
			
		||||
  if (resource == NULL)
 | 
			
		||||
    goto no_mem;
 | 
			
		||||
 | 
			
		||||
  resource->dispatch_func = link_dispatch_func;
 | 
			
		||||
  resource->dispatch_data = global;
 | 
			
		||||
  pinos_resource_set_dispatch (resource,
 | 
			
		||||
                               link_dispatch_func,
 | 
			
		||||
                               global);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("link %p: bound to %d", global->object, resource->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -789,16 +790,15 @@ link_bind_func (PinosGlobal *global,
 | 
			
		|||
  info.output_port_id = this->output ? this->output->port_id : -1;
 | 
			
		||||
  info.input_node_id = this->input ? this->input->node->global->id : -1;
 | 
			
		||||
  info.input_port_id = this->input ? this->input->port_id : -1;
 | 
			
		||||
  pinos_resource_send_message (resource,
 | 
			
		||||
                               PINOS_MESSAGE_LINK_INFO,
 | 
			
		||||
                               &m,
 | 
			
		||||
                               true);
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
  return pinos_resource_send_message (resource,
 | 
			
		||||
                                      PINOS_MESSAGE_LINK_INFO,
 | 
			
		||||
                                      &m,
 | 
			
		||||
                                      true);
 | 
			
		||||
no_mem:
 | 
			
		||||
  pinos_resource_send_error (client->core_resource,
 | 
			
		||||
                             SPA_RESULT_NO_MEMORY,
 | 
			
		||||
                             "no memory");
 | 
			
		||||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PinosLink *
 | 
			
		||||
| 
						 | 
				
			
			@ -853,6 +853,7 @@ pinos_link_new (PinosCore       *core,
 | 
			
		|||
  spa_list_insert (core->link_list.prev, &this->link);
 | 
			
		||||
 | 
			
		||||
  this->global = pinos_core_add_global (core,
 | 
			
		||||
                                        NULL,
 | 
			
		||||
                                        core->uri.link,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
pinoscore_headers = [
 | 
			
		||||
  'access.h',
 | 
			
		||||
  'client.h',
 | 
			
		||||
  'client-node.h',
 | 
			
		||||
  'command.h',
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +15,7 @@ pinoscore_headers = [
 | 
			
		|||
]
 | 
			
		||||
 | 
			
		||||
pinoscore_sources = [
 | 
			
		||||
  'access.c',
 | 
			
		||||
  'client.c',
 | 
			
		||||
  'client-node.c',
 | 
			
		||||
  'command.c',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -107,7 +107,7 @@ module_dispatch_func (void             *object,
 | 
			
		|||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static SpaResult
 | 
			
		||||
module_bind_func (PinosGlobal *global,
 | 
			
		||||
                  PinosClient *client,
 | 
			
		||||
                  uint32_t     version,
 | 
			
		||||
| 
						 | 
				
			
			@ -120,14 +120,15 @@ module_bind_func (PinosGlobal *global,
 | 
			
		|||
 | 
			
		||||
  resource = pinos_resource_new (client,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 global->core->uri.module,
 | 
			
		||||
                                 global->type,
 | 
			
		||||
                                 global->object,
 | 
			
		||||
                                 NULL);
 | 
			
		||||
  if (resource == NULL)
 | 
			
		||||
    goto no_mem;
 | 
			
		||||
 | 
			
		||||
  resource->dispatch_func = module_dispatch_func;
 | 
			
		||||
  resource->dispatch_data = global;
 | 
			
		||||
  pinos_resource_set_dispatch (resource,
 | 
			
		||||
                               module_dispatch_func,
 | 
			
		||||
                               global);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("module %p: bound to %d", global->object, resource->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,16 +140,15 @@ module_bind_func (PinosGlobal *global,
 | 
			
		|||
  info.args = this->args;
 | 
			
		||||
  info.props = NULL;
 | 
			
		||||
 | 
			
		||||
  pinos_resource_send_message (resource,
 | 
			
		||||
                               PINOS_MESSAGE_MODULE_INFO,
 | 
			
		||||
                               &m,
 | 
			
		||||
                               true);
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
  return pinos_resource_send_message (resource,
 | 
			
		||||
                                      PINOS_MESSAGE_MODULE_INFO,
 | 
			
		||||
                                      &m,
 | 
			
		||||
                                      true);
 | 
			
		||||
no_mem:
 | 
			
		||||
  pinos_resource_send_error (resource,
 | 
			
		||||
                             SPA_RESULT_NO_MEMORY,
 | 
			
		||||
                             "no memory");
 | 
			
		||||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -226,6 +226,7 @@ pinos_module_load (PinosCore    *core,
 | 
			
		|||
  pinos_log_debug ("loaded module: %s", this->name);
 | 
			
		||||
 | 
			
		||||
  this->global = pinos_core_add_global (core,
 | 
			
		||||
                                        NULL,
 | 
			
		||||
                                        core->uri.module,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        impl,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -406,7 +406,7 @@ node_unbind_func (void *data)
 | 
			
		|||
  spa_list_remove (&resource->link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
static SpaResult
 | 
			
		||||
node_bind_func (PinosGlobal *global,
 | 
			
		||||
                PinosClient *client,
 | 
			
		||||
                uint32_t     version,
 | 
			
		||||
| 
						 | 
				
			
			@ -419,14 +419,15 @@ node_bind_func (PinosGlobal *global,
 | 
			
		|||
 | 
			
		||||
  resource = pinos_resource_new (client,
 | 
			
		||||
                                 id,
 | 
			
		||||
                                 global->core->uri.registry,
 | 
			
		||||
                                 global->type,
 | 
			
		||||
                                 global->object,
 | 
			
		||||
                                 node_unbind_func);
 | 
			
		||||
  if (resource == NULL)
 | 
			
		||||
    goto no_mem;
 | 
			
		||||
 | 
			
		||||
  resource->dispatch_func = node_dispatch_func;
 | 
			
		||||
  resource->dispatch_data = global;
 | 
			
		||||
  pinos_resource_set_dispatch (resource,
 | 
			
		||||
                               node_dispatch_func,
 | 
			
		||||
                               global);
 | 
			
		||||
 | 
			
		||||
  pinos_log_debug ("node %p: bound to %d", this, resource->id);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -440,16 +441,15 @@ node_bind_func (PinosGlobal *global,
 | 
			
		|||
  info.error = this->error;
 | 
			
		||||
  info.props = this->properties ? &this->properties->dict : NULL;
 | 
			
		||||
 | 
			
		||||
  pinos_resource_send_message (resource,
 | 
			
		||||
                               PINOS_MESSAGE_NODE_INFO,
 | 
			
		||||
                               &m,
 | 
			
		||||
                               true);
 | 
			
		||||
  return;
 | 
			
		||||
 | 
			
		||||
  return pinos_resource_send_message (resource,
 | 
			
		||||
                                      PINOS_MESSAGE_NODE_INFO,
 | 
			
		||||
                                      &m,
 | 
			
		||||
                                      true);
 | 
			
		||||
no_mem:
 | 
			
		||||
  pinos_resource_send_error (resource,
 | 
			
		||||
                             SPA_RESULT_NO_MEMORY,
 | 
			
		||||
                             "no memory");
 | 
			
		||||
  return SPA_RESULT_NO_MEMORY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -466,6 +466,7 @@ init_complete (PinosNode *this)
 | 
			
		|||
  pinos_node_update_state (this, PINOS_NODE_STATE_SUSPENDED, NULL);
 | 
			
		||||
 | 
			
		||||
  this->global = pinos_core_add_global (this->core,
 | 
			
		||||
                                        NULL,
 | 
			
		||||
                                        this->core->uri.node,
 | 
			
		||||
                                        0,
 | 
			
		||||
                                        this,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,6 +21,13 @@
 | 
			
		|||
 | 
			
		||||
#include "pinos/server/resource.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  PinosResource this;
 | 
			
		||||
 | 
			
		||||
  PinosDispatchFunc  dispatch_func;
 | 
			
		||||
  void              *dispatch_data;
 | 
			
		||||
} PinosResourceImpl;
 | 
			
		||||
 | 
			
		||||
PinosResource *
 | 
			
		||||
pinos_resource_new (PinosClient *client,
 | 
			
		||||
                    uint32_t     id,
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +35,15 @@ pinos_resource_new (PinosClient *client,
 | 
			
		|||
                    void        *object,
 | 
			
		||||
                    PinosDestroy destroy)
 | 
			
		||||
{
 | 
			
		||||
  PinosResourceImpl *impl;
 | 
			
		||||
  PinosResource *this;
 | 
			
		||||
 | 
			
		||||
  this = calloc (1, sizeof (PinosResource));
 | 
			
		||||
  if (this == NULL)
 | 
			
		||||
  impl = calloc (1, sizeof (PinosResourceImpl));
 | 
			
		||||
  if (impl == NULL)
 | 
			
		||||
    return NULL;
 | 
			
		||||
 | 
			
		||||
  this = &impl->this;
 | 
			
		||||
 | 
			
		||||
  this->core = client->core;
 | 
			
		||||
  this->client = client;
 | 
			
		||||
  this->id = id;
 | 
			
		||||
| 
						 | 
				
			
			@ -41,9 +51,6 @@ pinos_resource_new (PinosClient *client,
 | 
			
		|||
  this->object = object;
 | 
			
		||||
  this->destroy = destroy;
 | 
			
		||||
 | 
			
		||||
  this->send_func = client->send_func;
 | 
			
		||||
  this->send_data = client->send_data;
 | 
			
		||||
 | 
			
		||||
  pinos_signal_init (&this->destroy_signal);
 | 
			
		||||
 | 
			
		||||
  this->id = pinos_map_insert_new (&client->objects, this);
 | 
			
		||||
| 
						 | 
				
			
			@ -92,23 +99,82 @@ pinos_resource_destroy (PinosResource *resource)
 | 
			
		|||
  return SPA_RESULT_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
pinos_resource_set_dispatch (PinosResource     *resource,
 | 
			
		||||
                             PinosDispatchFunc  func,
 | 
			
		||||
                             void              *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosResourceImpl *impl = SPA_CONTAINER_OF (resource, PinosResourceImpl, this);
 | 
			
		||||
 | 
			
		||||
  impl->dispatch_func = func;
 | 
			
		||||
  impl->dispatch_data = data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SpaResult
 | 
			
		||||
do_dispatch_message (PinosAccessData *data)
 | 
			
		||||
{
 | 
			
		||||
  PinosResourceImpl *impl = SPA_CONTAINER_OF (data->resource, PinosResourceImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (data->res == SPA_RESULT_NO_PERMISSION) {
 | 
			
		||||
    pinos_resource_send_error (data->resource,
 | 
			
		||||
                               data->res,
 | 
			
		||||
                               "no permission");
 | 
			
		||||
  } else if (SPA_RESULT_IS_ERROR (data->res)) {
 | 
			
		||||
    pinos_resource_send_error (data->resource,
 | 
			
		||||
                               data->res,
 | 
			
		||||
                               "error %d", data->res);
 | 
			
		||||
  } else {
 | 
			
		||||
    data->res = impl->dispatch_func (data->resource,
 | 
			
		||||
                                     data->opcode,
 | 
			
		||||
                                     data->message,
 | 
			
		||||
                                     impl->dispatch_data);
 | 
			
		||||
  }
 | 
			
		||||
  return data->res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_resource_dispatch (PinosResource *resource,
 | 
			
		||||
                         uint32_t       opcode,
 | 
			
		||||
                         void          *message)
 | 
			
		||||
{
 | 
			
		||||
  PinosResourceImpl *impl = SPA_CONTAINER_OF (resource, PinosResourceImpl, this);
 | 
			
		||||
 | 
			
		||||
  if (impl->dispatch_func) {
 | 
			
		||||
    PinosAccessData data;
 | 
			
		||||
 | 
			
		||||
    data.client = resource->client;
 | 
			
		||||
    data.resource = resource;
 | 
			
		||||
    data.opcode = opcode;
 | 
			
		||||
    data.message = message;
 | 
			
		||||
    data.flush = false;
 | 
			
		||||
 | 
			
		||||
    data.res = SPA_RESULT_OK;
 | 
			
		||||
    pinos_signal_emit (&resource->core->access.check_dispatch,
 | 
			
		||||
                       do_dispatch_message,
 | 
			
		||||
                       &data);
 | 
			
		||||
 | 
			
		||||
    if (SPA_RESULT_IS_ASYNC (data.res))
 | 
			
		||||
      return data.res;
 | 
			
		||||
 | 
			
		||||
    return do_dispatch_message (&data);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pinos_log_error ("resource %p: dispatch func not implemented", resource);
 | 
			
		||||
 | 
			
		||||
  return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
pinos_resource_send_message (PinosResource     *resource,
 | 
			
		||||
                             uint32_t           opcode,
 | 
			
		||||
                             void              *message,
 | 
			
		||||
                             bool               flush)
 | 
			
		||||
{
 | 
			
		||||
  if (!resource->send_func) {
 | 
			
		||||
    pinos_log_error ("resource %p: send func not implemented", resource);
 | 
			
		||||
    return SPA_RESULT_NOT_IMPLEMENTED;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return resource->send_func (resource,
 | 
			
		||||
                              resource->id,
 | 
			
		||||
                              opcode,
 | 
			
		||||
                              message,
 | 
			
		||||
                              flush,
 | 
			
		||||
                              resource->send_data);
 | 
			
		||||
  return pinos_client_send_message (resource->client,
 | 
			
		||||
                                    resource,
 | 
			
		||||
                                    opcode,
 | 
			
		||||
                                    message,
 | 
			
		||||
                                    flush);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SpaResult
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,17 +29,14 @@ extern "C" {
 | 
			
		|||
 | 
			
		||||
typedef struct _PinosResource PinosResource;
 | 
			
		||||
 | 
			
		||||
#include <spa/include/spa/list.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/client/sig.h>
 | 
			
		||||
 | 
			
		||||
#include <pinos/server/core.h>
 | 
			
		||||
 | 
			
		||||
typedef void  (*PinosDestroy)  (void *object);
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosSendFunc) (void             *object,
 | 
			
		||||
                                    uint32_t          id,
 | 
			
		||||
                                    uint32_t          opcode,
 | 
			
		||||
                                    void             *message,
 | 
			
		||||
                                    bool              flush,
 | 
			
		||||
                                    void             *data);
 | 
			
		||||
 | 
			
		||||
typedef SpaResult (*PinosDispatchFunc) (void             *object,
 | 
			
		||||
                                        uint32_t          opcode,
 | 
			
		||||
                                        void             *message,
 | 
			
		||||
| 
						 | 
				
			
			@ -56,22 +53,25 @@ struct _PinosResource {
 | 
			
		|||
  void         *object;
 | 
			
		||||
  PinosDestroy  destroy;
 | 
			
		||||
 | 
			
		||||
  PinosSendFunc      send_func;
 | 
			
		||||
  void              *send_data;
 | 
			
		||||
  PinosDispatchFunc  dispatch_func;
 | 
			
		||||
  void              *dispatch_data;
 | 
			
		||||
 | 
			
		||||
  PINOS_SIGNAL (destroy_signal, (PinosListener *listener,
 | 
			
		||||
                                 PinosResource *resource));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PinosResource * pinos_resource_new                (PinosClient  *client,
 | 
			
		||||
                                                   uint32_t      id,
 | 
			
		||||
                                                   uint32_t      type,
 | 
			
		||||
                                                   void         *object,
 | 
			
		||||
                                                   PinosDestroy  destroy);
 | 
			
		||||
PinosResource * pinos_resource_new                (PinosClient   *client,
 | 
			
		||||
                                                   uint32_t       id,
 | 
			
		||||
                                                   uint32_t       type,
 | 
			
		||||
                                                   void          *object,
 | 
			
		||||
                                                   PinosDestroy   destroy);
 | 
			
		||||
SpaResult       pinos_resource_destroy            (PinosResource *resource);
 | 
			
		||||
 | 
			
		||||
void            pinos_resource_set_dispatch       (PinosResource     *resource,
 | 
			
		||||
                                                   PinosDispatchFunc  func,
 | 
			
		||||
                                                   void              *data);
 | 
			
		||||
 | 
			
		||||
SpaResult       pinos_resource_dispatch           (PinosResource     *resource,
 | 
			
		||||
                                                   uint32_t           opcode,
 | 
			
		||||
                                                   void              *message);
 | 
			
		||||
 | 
			
		||||
SpaResult       pinos_resource_send_message       (PinosResource     *resource,
 | 
			
		||||
                                                   uint32_t           opcode,
 | 
			
		||||
                                                   void              *message,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,32 +178,31 @@ dump_object (PinosContext           *context,
 | 
			
		|||
    pinos_context_get_core_info (context,
 | 
			
		||||
                                 dump_core_info,
 | 
			
		||||
                                 data);
 | 
			
		||||
  }
 | 
			
		||||
  if (type == context->uri.node) {
 | 
			
		||||
  } else if (type == context->uri.node) {
 | 
			
		||||
    pinos_context_get_node_info_by_id (context,
 | 
			
		||||
                                       id,
 | 
			
		||||
                                       dump_node_info,
 | 
			
		||||
                                       data);
 | 
			
		||||
  }
 | 
			
		||||
  if (type == context->uri.module) {
 | 
			
		||||
  } else if (type == context->uri.module) {
 | 
			
		||||
    pinos_context_get_module_info_by_id (context,
 | 
			
		||||
                                         id,
 | 
			
		||||
                                         dump_module_info,
 | 
			
		||||
                                         data);
 | 
			
		||||
  }
 | 
			
		||||
  if (type == context->uri.client) {
 | 
			
		||||
  } else if (type == context->uri.client) {
 | 
			
		||||
    pinos_context_get_client_info_by_id (context,
 | 
			
		||||
                                         id,
 | 
			
		||||
                                         dump_client_info,
 | 
			
		||||
                                         data);
 | 
			
		||||
  }
 | 
			
		||||
  if (type == context->uri.link) {
 | 
			
		||||
  } else if (type == context->uri.link) {
 | 
			
		||||
    pinos_context_get_link_info_by_id (context,
 | 
			
		||||
                                       id,
 | 
			
		||||
                                       dump_link_info,
 | 
			
		||||
                                       data);
 | 
			
		||||
  } else {
 | 
			
		||||
    printf ("\tid: %u\n", id);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,6 +67,8 @@ typedef enum {
 | 
			
		|||
  SPA_RESULT_ASYNC_BUSY                = -30,
 | 
			
		||||
  SPA_RESULT_INVALID_OBJECT_ID         = -31,
 | 
			
		||||
  SPA_RESULT_NO_MEMORY                 = -32,
 | 
			
		||||
  SPA_RESULT_NO_PERMISSION             = -33,
 | 
			
		||||
  SPA_RESULT_SKIPPED                   = -34,
 | 
			
		||||
} SpaResult;
 | 
			
		||||
 | 
			
		||||
#define SPA_ASYNC_MASK                  (3 << 30)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,21 +1,21 @@
 | 
			
		|||
spa_headers = [
 | 
			
		||||
  'barrier.h',
 | 
			
		||||
  'buffer.h',
 | 
			
		||||
  'clock.h',
 | 
			
		||||
  'control.h',
 | 
			
		||||
  'debug.h',
 | 
			
		||||
  'defs.h',
 | 
			
		||||
  'dict.h',
 | 
			
		||||
  'format.h',
 | 
			
		||||
  'id-map.h',
 | 
			
		||||
  'list.h',
 | 
			
		||||
  'log.h',
 | 
			
		||||
  'loop.h',
 | 
			
		||||
  'monitor.h',
 | 
			
		||||
  'node-command.h',
 | 
			
		||||
  'node-event.h',
 | 
			
		||||
  'node.h',
 | 
			
		||||
  'plugin.h',
 | 
			
		||||
  'poll.h',
 | 
			
		||||
  'port.h',
 | 
			
		||||
  'props.h',
 | 
			
		||||
  'queue.h',
 | 
			
		||||
  'ringbuffer.h'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue