diff --git a/pinos/client/connection.c b/pinos/client/connection.c index fa7299bf1..e39c6f313 100644 --- a/pinos/client/connection.c +++ b/pinos/client/connection.c @@ -98,6 +98,17 @@ connection_parse_client_update (PinosConnection *conn, PinosMessageClientUpdate m->props = pinos_serialize_dict_deserialize (p, SPA_PTR_TO_INT (m->props)); } +static void +connection_parse_error (PinosConnection *conn, PinosMessageError *m) +{ + void *p; + + p = conn->in.data; + memcpy (m, p, sizeof (PinosMessageError)); + if (m->error) + m->error = SPA_MEMBER (p, SPA_PTR_TO_INT (m->error), const char); +} + static void connection_parse_notify_global (PinosConnection *conn, PinosMessageNotifyGlobal *ng) { @@ -198,6 +209,8 @@ connection_parse_node_info (PinosConnection *conn, PinosMessageNodeInfo *m) if (m->info->name) m->info->name = SPA_MEMBER (di, SPA_PTR_TO_INT (m->info->name), const char); + if (m->info->error) + m->info->error = SPA_MEMBER (di, SPA_PTR_TO_INT (m->info->error), const char); if (m->info->props) m->info->props = pinos_serialize_dict_deserialize (di, SPA_PTR_TO_INT (m->info->props)); } @@ -374,6 +387,29 @@ connection_add_client_update (PinosConnection *conn, } } +static void +connection_add_error (PinosConnection *conn, + uint32_t dest_id, + PinosMessageError *m) +{ + size_t len; + void *p; + PinosMessageError *d; + + /* calc len */ + len = sizeof (PinosMessageError); + len += m->error ? strlen (m->error) + 1 : 0; + + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_ERROR, len); + memcpy (p, m, sizeof (PinosMessageError)); + d = p; + + if (m->error) { + strcpy (p, m->error); + d->error = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + } +} + static void connection_add_notify_global (PinosConnection *conn, uint32_t dest_id, @@ -593,6 +629,7 @@ connection_add_node_info (PinosConnection *conn, uint32_t dest_id, PinosMessageN if (m->info) { len += sizeof (PinosNodeInfo); len += m->info->name ? strlen (m->info->name) + 1 : 0; + len += m->info->error ? strlen (m->info->error) + 1 : 0; len += pinos_serialize_dict_get_size (m->info->props); } @@ -615,6 +652,12 @@ connection_add_node_info (PinosConnection *conn, uint32_t dest_id, PinosMessageN di->name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, di)); p += slen; } + if (m->info->error) { + slen = strlen (m->info->error) + 1; + memcpy (p, m->info->error, slen); + di->error = SPA_INT_TO_PTR (SPA_PTRDIFF (p, di)); + p += slen; + } if (m->info->props) { len = pinos_serialize_dict_serialize (p, m->info->props); di->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, di)); @@ -952,7 +995,11 @@ pinos_connection_new (int fd) PinosConnection *c; c = calloc (1, sizeof (PinosConnection)); + if (c == NULL) + return NULL; + pinos_log_debug ("connection %p: new", c); + c->fd = fd; c->out.buffer_data = malloc (MAX_BUFFER_SIZE); c->out.buffer_maxsize = MAX_BUFFER_SIZE; @@ -960,7 +1007,16 @@ pinos_connection_new (int fd) c->in.buffer_maxsize = MAX_BUFFER_SIZE; c->in.update = true; + if (c->out.buffer_data == NULL || c->in.buffer_data == NULL) + goto no_mem; + return c; + +no_mem: + free (c->out.buffer_data); + free (c->in.buffer_data); + free (c); + return NULL; } void @@ -1069,6 +1125,10 @@ pinos_connection_parse_message (PinosConnection *conn, memcpy (message, conn->in.data, sizeof (PinosMessageNotifyDone)); break; + case PINOS_MESSAGE_ERROR: + connection_parse_error (conn, message); + break; + case PINOS_MESSAGE_GET_REGISTRY: if (conn->in.size < sizeof (PinosMessageGetRegistry)) return false; @@ -1265,6 +1325,10 @@ pinos_connection_add_message (PinosConnection *conn, memcpy (p, message, sizeof (PinosMessageNotifyDone)); break; + case PINOS_MESSAGE_ERROR: + connection_add_error (conn, dest_id, message); + break; + case PINOS_MESSAGE_GET_REGISTRY: p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageGetRegistry)); memcpy (p, message, sizeof (PinosMessageGetRegistry)); diff --git a/pinos/client/connection.h b/pinos/client/connection.h index 4f8abb0e1..ed28606d7 100644 --- a/pinos/client/connection.h +++ b/pinos/client/connection.h @@ -39,6 +39,7 @@ typedef enum { PINOS_MESSAGE_SYNC, PINOS_MESSAGE_NOTIFY_DONE, + PINOS_MESSAGE_ERROR, PINOS_MESSAGE_GET_REGISTRY, PINOS_MESSAGE_REMOVE_ID, PINOS_MESSAGE_CORE_INFO, @@ -103,6 +104,13 @@ typedef struct { uint32_t seq; } PinosMessageNotifyDone; +/* PINOS_MESSAGE_ERROR */ +typedef struct { + uint32_t id; + SpaResult res; + const char *error; +} PinosMessageError; + /* PINOS_MESSAGE_GET_REGISTRY */ typedef struct { uint32_t seq; @@ -148,7 +156,7 @@ typedef struct { /* PINOS_MESSAGE_NOTIFY_GLOBAL */ typedef struct { uint32_t id; - const char * type; + const char *type; } PinosMessageNotifyGlobal; /* PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE */ diff --git a/pinos/client/context.c b/pinos/client/context.c index 41bbc0778..dd467b4a5 100644 --- a/pinos/client/context.c +++ b/pinos/client/context.c @@ -37,9 +37,6 @@ typedef struct { SpaSource source; bool disconnecting; - - PinosSubscriptionFunc subscribe_func; - void *subscribe_data; } PinosContextImpl; /** @@ -112,6 +109,7 @@ core_dispatch_func (void *object, PinosSubscriptionEvent event; pinos_log_debug ("got core info %d", type); + if (proxy->user_data == NULL) event = PINOS_SUBSCRIPTION_EVENT_NEW; else @@ -119,13 +117,11 @@ core_dispatch_func (void *object, proxy->user_data = pinos_core_info_update (proxy->user_data, m->info); - if (impl->subscribe_func) { - impl->subscribe_func (this, - event, - proxy->type, - proxy->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + event, + proxy->type, + proxy->id); break; } case PINOS_MESSAGE_NOTIFY_DONE: @@ -136,6 +132,12 @@ core_dispatch_func (void *object, context_set_state (this, PINOS_CONTEXT_STATE_CONNECTED, NULL); break; } + case PINOS_MESSAGE_ERROR: + { + PinosMessageError *m = message; + context_set_state (this, PINOS_CONTEXT_STATE_ERROR, m->error); + break; + } case PINOS_MESSAGE_REMOVE_ID: { PinosMessageRemoveId *m = message; @@ -180,13 +182,11 @@ module_dispatch_func (void *object, proxy->user_data = pinos_module_info_update (proxy->user_data, m->info); - if (impl->subscribe_func) { - impl->subscribe_func (this, - event, - proxy->type, - proxy->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + event, + proxy->type, + proxy->id); break; } @@ -221,13 +221,11 @@ node_dispatch_func (void *object, proxy->user_data = pinos_node_info_update (proxy->user_data, m->info); - if (impl->subscribe_func) { - impl->subscribe_func (this, - event, - proxy->type, - proxy->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + event, + proxy->type, + proxy->id); break; } default: @@ -261,13 +259,11 @@ client_dispatch_func (void *object, proxy->user_data = pinos_client_info_update (proxy->user_data, m->info); - if (impl->subscribe_func) { - impl->subscribe_func (this, - event, - proxy->type, - proxy->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + event, + proxy->type, + proxy->id); break; } default: @@ -301,13 +297,11 @@ link_dispatch_func (void *object, proxy->user_data = pinos_link_info_update (proxy->user_data, m->info); - if (impl->subscribe_func) { - impl->subscribe_func (this, - event, - proxy->type, - proxy->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + event, + proxy->type, + proxy->id); break; } default: @@ -338,24 +332,32 @@ registry_dispatch_func (void *object, proxy = pinos_proxy_new (this, SPA_ID_INVALID, this->uri.node); + if (proxy == NULL) + goto no_mem; proxy->dispatch_func = node_dispatch_func; proxy->dispatch_data = 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; } 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; } 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; } @@ -376,13 +378,11 @@ registry_dispatch_func (void *object, PinosMessageNotifyGlobalRemove *ng = message; pinos_log_debug ("got global remove %u", ng->id); - if (impl->subscribe_func) { - impl->subscribe_func (this, - PINOS_SUBSCRIPTION_EVENT_REMOVE, - SPA_ID_INVALID, - ng->id, - impl->subscribe_data); - } + pinos_signal_emit (&this->subscription, + this, + PINOS_SUBSCRIPTION_EVENT_REMOVE, + SPA_ID_INVALID, + ng->id); break; } default: @@ -390,6 +390,9 @@ registry_dispatch_func (void *object, break; } return SPA_RESULT_OK; + +no_mem: + return SPA_RESULT_NO_MEMORY; } static void @@ -477,6 +480,9 @@ pinos_context_new (PinosLoop *loop, PinosContext *this; impl = calloc (1, sizeof (PinosContextImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; pinos_log_debug ("context %p: new", impl); @@ -484,6 +490,9 @@ pinos_context_new (PinosLoop *loop, if (properties == NULL) properties = pinos_properties_new ("application.name", name, NULL); + if (properties == NULL) + goto no_mem; + pinos_fill_context_properties (properties); this->properties = properties; @@ -503,9 +512,15 @@ pinos_context_new (PinosLoop *loop, spa_list_init (&this->proxy_list); pinos_signal_init (&this->state_changed); + pinos_signal_init (&this->subscription); pinos_signal_init (&this->destroy_signal); return this; + +no_mem: + free (this->name); + free (impl); + return NULL; } void @@ -523,14 +538,10 @@ pinos_context_destroy (PinosContext *context) spa_list_for_each_safe (proxy, t2, &context->proxy_list, link) pinos_proxy_destroy (proxy); - if (context->name) - free (context->name); + free (context->name); if (context->properties) pinos_properties_free (context->properties); - - if (context->error) - free (context->error); - + free (context->error); free (impl); } @@ -579,8 +590,7 @@ pinos_context_connect (PinosContext *context) if (name_size > (int)sizeof addr.sun_path) { pinos_log_error ("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", runtime_dir, name); - close (fd); - return false; + goto error_close; }; size = offsetof (struct sockaddr_un, sun_path) + name_size; @@ -589,12 +599,14 @@ pinos_context_connect (PinosContext *context) context_set_state (context, PINOS_CONTEXT_STATE_ERROR, "connect failed: %s", strerror (errno)); - close (fd); - return false; + goto error_close; } - impl->fd = fd; impl->connection = pinos_connection_new (fd); + if (impl->connection == NULL) + goto error_close; + + impl->fd = fd; pinos_loop_add_io (context->loop, fd, @@ -606,6 +618,9 @@ pinos_context_connect (PinosContext *context) context->core_proxy = pinos_proxy_new (context, SPA_ID_INVALID, context->uri.core); + if (context->core_proxy == NULL) + goto no_proxy; + context->core_proxy->dispatch_func = core_dispatch_func; context->core_proxy->dispatch_data = impl; @@ -618,6 +633,9 @@ pinos_context_connect (PinosContext *context) context->registry_proxy = pinos_proxy_new (context, SPA_ID_INVALID, context->uri.registry); + if (context->registry_proxy == NULL) + goto no_registry; + context->registry_proxy->dispatch_func = registry_dispatch_func; context->registry_proxy->dispatch_data = impl; @@ -628,6 +646,14 @@ pinos_context_connect (PinosContext *context) &grm, true); return true; + +no_registry: + pinos_proxy_destroy (context->core_proxy); +no_proxy: + pinos_connection_destroy (impl->connection); +error_close: + close (fd); + return false; } /** @@ -645,6 +671,8 @@ pinos_context_disconnect (PinosContext *context) impl->disconnecting = true; + pinos_proxy_destroy (context->registry_proxy); + pinos_proxy_destroy (context->core_proxy); pinos_connection_destroy (impl->connection); close (impl->fd); @@ -653,17 +681,6 @@ pinos_context_disconnect (PinosContext *context) return true; } -void -pinos_context_subscribe (PinosContext *context, - PinosSubscriptionFunc func, - void *data) -{ - PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this); - - impl->subscribe_func = func; - impl->subscribe_data = data; -} - void pinos_context_get_core_info (PinosContext *context, PinosCoreInfoCallback cb, diff --git a/pinos/client/context.h b/pinos/client/context.h index da4077114..4c67eb0e0 100644 --- a/pinos/client/context.h +++ b/pinos/client/context.h @@ -29,6 +29,7 @@ typedef struct _PinosContext PinosContext; #include #include #include +#include #include #include @@ -66,19 +67,25 @@ struct _PinosContext { PinosProxy *core_proxy; PinosProxy *registry_proxy; - PinosMap objects; + PinosMap objects; - SpaList global_list; - SpaList stream_list; - SpaList proxy_list; + SpaList global_list; + SpaList stream_list; + SpaList proxy_list; - PinosSendFunc send_func; - void *send_data; + PinosSendFunc send_func; + void *send_data; PinosContextState state; char *error; - PINOS_SIGNAL (state_changed, (PinosListener *listener, - PinosContext *context)); + PINOS_SIGNAL (state_changed, (PinosListener *listener, + PinosContext *context)); + + PINOS_SIGNAL (subscription, (PinosListener *listener, + PinosContext *context, + PinosSubscriptionEvent event, + uint32_t type, + uint32_t id)); PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosContext *context)); diff --git a/pinos/client/introspect.c b/pinos/client/introspect.c index a87a24a1f..7d5f4a59b 100644 --- a/pinos/client/introspect.c +++ b/pinos/client/introspect.c @@ -127,7 +127,11 @@ pinos_spa_dict_copy (SpaDict *dict) return NULL; copy = calloc (1, sizeof (SpaDict)); + if (copy == NULL) + goto no_mem; copy->items = calloc (dict->n_items, sizeof (SpaDictItem)); + if (copy->items == NULL) + goto no_items; copy->n_items = dict->n_items; for (i = 0; i < dict->n_items; i++) { @@ -135,6 +139,11 @@ pinos_spa_dict_copy (SpaDict *dict) copy->items[i].value = strdup (dict->items[i].value); } return copy; + +no_items: + free (copy); +no_mem: + return NULL; } PinosCoreInfo * @@ -148,6 +157,8 @@ pinos_core_info_update (PinosCoreInfo *info, if (info == NULL) { info = calloc (1, sizeof (PinosCoreInfo)); + if (info == NULL) + return NULL; change_mask = ~0; } else { change_mask = info->change_mask | update->change_mask; @@ -215,6 +226,8 @@ pinos_node_info_update (PinosNodeInfo *info, if (info == NULL) { info = calloc (1, sizeof (PinosNodeInfo)); + if (info == NULL) + return NULL; change_mask = ~0; } else { change_mask = info->change_mask | update->change_mask; @@ -229,6 +242,9 @@ pinos_node_info_update (PinosNodeInfo *info, } if (update->change_mask & (1 << 1)) { info->state = update->state; + if (info->error) + free ((void*)info->error); + info->error = update->error ? strdup (update->error) : NULL; } if (update->change_mask & (1 << 2)) { if (info->props) @@ -245,6 +261,8 @@ pinos_node_info_free (PinosNodeInfo *info) return; if (info->name) free ((void*)info->name); + if (info->error) + free ((void*)info->error); if (info->props) pinos_spa_dict_destroy (info->props); free (info); @@ -261,6 +279,8 @@ pinos_module_info_update (PinosModuleInfo *info, if (info == NULL) { info = calloc (1, sizeof (PinosModuleInfo)); + if (info == NULL) + return NULL; change_mask = ~0; } else { change_mask = info->change_mask | update->change_mask; @@ -320,6 +340,8 @@ pinos_client_info_update (PinosClientInfo *info, if (info == NULL) { info = calloc (1, sizeof (PinosClientInfo)); + if (info == NULL) + return NULL; change_mask = ~0; } else { change_mask = info->change_mask | update->change_mask; @@ -336,7 +358,7 @@ pinos_client_info_update (PinosClientInfo *info, } void -pinos_client_info_free (PinosClientInfo *info) +pinos_client_info_free (PinosClientInfo *info) { if (info == NULL) return; @@ -356,6 +378,8 @@ pinos_link_info_update (PinosLinkInfo *info, if (info == NULL) { info = calloc (1, sizeof (PinosLinkInfo)); + if (info == NULL) + return NULL; change_mask = ~0; } else { change_mask = info->change_mask | update->change_mask; @@ -376,7 +400,7 @@ pinos_link_info_update (PinosLinkInfo *info, } void -pinos_link_info_free (PinosLinkInfo *info) +pinos_link_info_free (PinosLinkInfo *info) { free (info); } diff --git a/pinos/client/introspect.h b/pinos/client/introspect.h index 1a20f27e8..7ef95a264 100644 --- a/pinos/client/introspect.h +++ b/pinos/client/introspect.h @@ -240,18 +240,20 @@ void pinos_context_get_client_info_by_id (PinosContext *co * @id: generic id of the node * @change_mask: bitfield of changed fields since last call * @name: name the node, suitable for display - * @props: the properties of the node * @state: the current state of the node + * @error: an error reason if @state is error + * @props: the properties of the node * * The node information. Extra information can be added in later * versions. */ struct _PinosNodeInfo { - uint32_t id; - uint64_t change_mask; - const char *name; - PinosNodeState state; - SpaDict *props; + uint32_t id; + uint64_t change_mask; + const char *name; + PinosNodeState state; + const char *error; + SpaDict *props; }; PinosNodeInfo * pinos_node_info_update (PinosNodeInfo *info, diff --git a/pinos/client/loop.c b/pinos/client/loop.c index f3f261ed7..ba62eaeef 100644 --- a/pinos/client/loop.c +++ b/pinos/client/loop.c @@ -312,6 +312,8 @@ loop_add_io (SpaLoopUtils *utils, SpaSourceImpl *source; source = calloc (1, sizeof (SpaSourceImpl)); + if (source == NULL) + return NULL; source->source.loop = &impl->loop; source->source.func = source_io_func; @@ -353,6 +355,8 @@ loop_add_idle (SpaLoopUtils *utils, SpaSourceImpl *source; source = calloc (1, sizeof (SpaSourceImpl)); + if (source == NULL) + return NULL; source->source.loop = &impl->loop; source->source.func = source_idle_func; @@ -408,6 +412,8 @@ loop_add_event (SpaLoopUtils *utils, SpaSourceImpl *source; source = calloc (1, sizeof (SpaSourceImpl)); + if (source == NULL) + return NULL; source->source.loop = &impl->loop; source->source.func = source_event_func; @@ -454,6 +460,8 @@ loop_add_timer (SpaLoopUtils *utils, SpaSourceImpl *source; source = calloc (1, sizeof (SpaSourceImpl)); + if (source == NULL) + return NULL; source->source.loop = &impl->loop; source->source.func = source_timer_func; @@ -516,6 +524,8 @@ loop_add_signal (SpaLoopUtils *utils, sigset_t mask; source = calloc (1, sizeof (SpaSourceImpl)); + if (source == NULL) + return NULL; source->source.loop = &impl->loop; source->source.func = source_signal_func; @@ -557,13 +567,14 @@ pinos_loop_new (void) PinosLoop *this; impl = calloc (1, sizeof (PinosLoopImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; impl->epoll_fd = epoll_create1 (EPOLL_CLOEXEC); - if (impl->epoll_fd == -1) { - free (impl); - return NULL; - } + if (impl->epoll_fd == -1) + goto no_epoll; spa_list_init (&impl->source_list); @@ -600,6 +611,10 @@ pinos_loop_new (void) spa_ringbuffer_init (&impl->buffer, DATAS_SIZE); return this; + +no_epoll: + free (impl); + return NULL; } void diff --git a/pinos/client/mem.c b/pinos/client/mem.c index 696dd255b..f1dbe8425 100644 --- a/pinos/client/mem.c +++ b/pinos/client/mem.c @@ -91,14 +91,14 @@ pinos_memblock_alloc (PinosMemblockFlags flags, mem->fd = memfd_create ("pinos-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); if (mem->fd == -1) { pinos_log_error ("Failed to create memfd: %s\n", strerror (errno)); - return SPA_RESULT_ERROR; + return SPA_RESULT_ERRNO; } #else char filename[] = "/dev/shm/spa-tmpfile.XXXXXX"; mem->fd = mkostemp (filename, O_CLOEXEC); if (mem->fd == -1) { pinos_log_error ("Failed to create temporary file: %s\n", strerror (errno)); - return SPA_RESULT_ERROR; + return SPA_RESULT_ERRNO; } unlink (filename); #endif @@ -106,7 +106,7 @@ pinos_memblock_alloc (PinosMemblockFlags flags, if (ftruncate (mem->fd, size) < 0) { pinos_log_warn ("Failed to truncate temporary file: %s", strerror (errno)); close (mem->fd); - return SPA_RESULT_ERROR; + return SPA_RESULT_ERRNO; } #ifdef USE_MEMFD if (flags & PINOS_MEMBLOCK_FLAG_SEAL) { @@ -125,11 +125,15 @@ pinos_memblock_alloc (PinosMemblockFlags flags, prot |= PROT_WRITE; mem->ptr = mmap (NULL, size, prot, MAP_SHARED, mem->fd, 0); + if (mem->ptr == MAP_FAILED) + return SPA_RESULT_NO_MEMORY; } else { mem->ptr = NULL; } } else { mem->ptr = malloc (size); + if (mem->ptr == NULL) + return SPA_RESULT_NO_MEMORY; mem->fd = -1; } return SPA_RESULT_OK; diff --git a/pinos/client/properties.c b/pinos/client/properties.c index e6e376172..30d2e4acb 100644 --- a/pinos/client/properties.c +++ b/pinos/client/properties.c @@ -78,6 +78,9 @@ pinos_properties_new (const char *key, ...) const char *value; impl = calloc (1, sizeof (PinosPropertiesImpl)); + if (impl == NULL) + return NULL; + pinos_array_init (&impl->items); va_start (varargs, key); @@ -106,6 +109,9 @@ pinos_properties_new_dict (const SpaDict *dict) PinosPropertiesImpl *impl; impl = calloc (1, sizeof (PinosPropertiesImpl)); + if (impl == NULL) + return NULL; + pinos_array_init (&impl->items); for (i = 0; i < dict->n_items; i++) @@ -130,6 +136,9 @@ pinos_properties_copy (PinosProperties *properties) SpaDictItem *item; copy = pinos_properties_new (NULL, NULL); + if (copy == NULL) + return NULL; + pinos_array_for_each (item, &impl->items) add_func (copy, strdup (item->key), strdup (item->value)); @@ -154,6 +163,9 @@ pinos_properties_merge (PinosProperties *oldprops, void * state = NULL; res = pinos_properties_copy (oldprops); + if (res == NULL) + return NULL; + while ((key = pinos_properties_iterate (newprops, &state))) { pinos_properties_set (res, key, diff --git a/pinos/client/proxy.c b/pinos/client/proxy.c index 1311d7a30..daa976168 100644 --- a/pinos/client/proxy.c +++ b/pinos/client/proxy.c @@ -33,6 +33,9 @@ pinos_proxy_new (PinosContext *context, PinosProxy *this; impl = calloc (1, sizeof (PinosProxyImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; this->context = context; diff --git a/pinos/client/rtkit.c b/pinos/client/rtkit.c index 36dd7492b..1468d6aba 100644 --- a/pinos/client/rtkit.c +++ b/pinos/client/rtkit.c @@ -64,6 +64,9 @@ pinos_rtkit_bus_get_system (void) dbus_error_init(&error); bus = calloc (1, sizeof (PinosRTKitBus)); + if (bus == NULL) + return NULL; + bus->bus = dbus_bus_get_private (DBUS_BUS_SYSTEM, &error); if (bus->bus == NULL) goto error; diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 369685cba..c8dcb4e6f 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -173,19 +173,25 @@ pinos_stream_new (PinosContext *context, PinosStream *this; impl = calloc (1, sizeof (PinosStreamImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; pinos_log_debug ("stream %p: new", impl); - this->context = context; - this->name = strdup (name); - if (props == NULL) { props = pinos_properties_new ("media.name", name, NULL); } else if (!pinos_properties_get (props, "media.name")) { pinos_properties_set (props, "media.name", name); } + if (props == NULL) + goto no_mem; + this->properties = props; + this->context = context; + this->name = strdup (name); + pinos_signal_init (&this->destroy_signal); pinos_signal_init (&this->state_changed); pinos_signal_init (&this->format_changed); @@ -206,6 +212,10 @@ pinos_stream_new (PinosContext *context, spa_list_insert (&context->stream_list, &this->link); return this; + +no_mem: + free (impl); + return NULL; } void diff --git a/pinos/client/subscribe.h b/pinos/client/subscribe.h index 490fbe11b..4f89c2a0a 100644 --- a/pinos/client/subscribe.h +++ b/pinos/client/subscribe.h @@ -48,16 +48,6 @@ typedef enum { PINOS_SUBSCRIPTION_EVENT_REMOVE = 2, } PinosSubscriptionEvent; -typedef void (*PinosSubscriptionFunc) (PinosContext *context, - PinosSubscriptionEvent event, - uint32_t type, - uint32_t id, - void *data); - -void pinos_context_subscribe (PinosContext *context, - PinosSubscriptionFunc func, - void *data); - #ifdef __cplusplus } #endif diff --git a/pinos/client/thread-mainloop.c b/pinos/client/thread-mainloop.c index b43bd292d..d56e2fa26 100644 --- a/pinos/client/thread-mainloop.c +++ b/pinos/client/thread-mainloop.c @@ -83,12 +83,14 @@ pinos_thread_main_loop_new (PinosLoop *loop, pthread_mutexattr_t attr; impl = calloc (1, sizeof (PinosThreadMainLoopImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; pinos_log_debug ("thread-mainloop %p: new", impl); this->loop = loop; - if (name) - this->name = strdup (name); + this->name = name ? strdup (name) : NULL; pinos_loop_set_hooks (loop, pre_hook, @@ -97,7 +99,6 @@ pinos_thread_main_loop_new (PinosLoop *loop, pinos_signal_init (&this->destroy_signal); - pthread_mutexattr_init (&attr); pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutex_init (&impl->lock, &attr); diff --git a/pinos/client/transport.c b/pinos/client/transport.c index 7d842d7d3..e8c9eb442 100644 --- a/pinos/client/transport.c +++ b/pinos/client/transport.c @@ -99,6 +99,9 @@ pinos_transport_new (unsigned int max_inputs, area.n_outputs = 0; impl = calloc (1, sizeof (PinosTransportImpl)); + if (impl == NULL) + return NULL; + impl->offset = 0; trans = &impl->trans; @@ -124,6 +127,9 @@ pinos_transport_new_from_info (PinosTransportInfo *info) void *tmp; impl = calloc (1, sizeof (PinosTransportImpl)); + if (impl == NULL) + return NULL; + trans = &impl->trans; pinos_signal_init (&trans->destroy_signal); diff --git a/pinos/gst/gstpinosdeviceprovider.c b/pinos/gst/gstpinosdeviceprovider.c index e421f4713..38683cf15 100644 --- a/pinos/gst/gstpinosdeviceprovider.c +++ b/pinos/gst/gstpinosdeviceprovider.c @@ -254,14 +254,14 @@ find_device (GstDeviceProvider *provider, uint32_t id) } static void -context_subscribe_cb (PinosContext *context, - PinosSubscriptionEvent event, - uint32_t type, - uint32_t id, - void *user_data) +on_context_subscription (PinosListener *listener, + PinosContext *context, + PinosSubscriptionEvent event, + uint32_t type, + uint32_t id) { - GstPinosDeviceProvider *self = user_data; - GstDeviceProvider *provider = user_data; + GstPinosDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPinosDeviceProvider, ctx_subscription); + GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); GstPinosDevice *dev; if (type != context->uri.node) @@ -442,11 +442,12 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) goto failed_context; } - pinos_signal_add (&self->context->state_changed, &self->ctx_state_changed, on_context_state_changed); - - pinos_context_subscribe (self->context, - context_subscribe_cb, - self); + pinos_signal_add (&self->context->state_changed, + &self->ctx_state_changed, + on_context_state_changed); + pinos_signal_add (&self->context->subscription, + &self->ctx_subscription, + on_context_subscription); pinos_context_connect (self->context); for (;;) { diff --git a/pinos/gst/gstpinosdeviceprovider.h b/pinos/gst/gstpinosdeviceprovider.h index 4024f9428..2790f4cf1 100644 --- a/pinos/gst/gstpinosdeviceprovider.h +++ b/pinos/gst/gstpinosdeviceprovider.h @@ -85,6 +85,7 @@ struct _GstPinosDeviceProvider { PinosContext *context; PinosListener ctx_state_changed; + PinosListener ctx_subscription; }; struct _GstPinosDeviceProviderClass { diff --git a/pinos/modules/module-autolink.c b/pinos/modules/module-autolink.c index 3d22702f3..3e0901dad 100644 --- a/pinos/modules/module-autolink.c +++ b/pinos/modules/module-autolink.c @@ -111,28 +111,31 @@ on_link_state_changed (PinosListener *listener, switch (state) { case PINOS_LINK_STATE_ERROR: { + PinosResource *resource; + pinos_log_debug ("module %p: link %p: state error: %s", impl, link, link->error); + spa_list_for_each (resource, &link->resource_list, link) { + pinos_resource_send_error (resource, + SPA_RESULT_ERROR, + link->error); + } +#if 0 if (link->input && link->input->node) pinos_node_update_state (link->input->node, PINOS_NODE_STATE_ERROR, strdup (link->error)); if (link->output && link->output->node) pinos_node_update_state (link->output->node, PINOS_NODE_STATE_ERROR, strdup (link->error)); +#endif break; } case PINOS_LINK_STATE_UNLINKED: pinos_log_debug ("module %p: link %p: unlinked", impl, link); - #if 0 - g_set_error (&error, - PINOS_ERROR, - PINOS_ERROR_NODE_LINK, - "error node unlinked"); - if (link->input && link->input->node) - pinos_node_report_error (link->input->node, g_error_copy (error)); + pinos_node_update_state (link->input->node, PINOS_NODE_STATE_ERROR, strdup ("node unlinked")); if (link->output && link->output->node) - pinos_node_report_error (link->output->node, g_error_copy (error)); + pinos_node_update_state (link->output->node, PINOS_NODE_STATE_ERROR, strdup ("node unlinked")); #endif break; diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 2a1147b35..09d4da587 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -1234,6 +1234,9 @@ pinos_client_node_new (PinosClient *client, PinosClientNode *this; impl = calloc (1, sizeof (PinosClientNodeImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; impl->core = client->core; impl->data_fd = -1; @@ -1248,6 +1251,8 @@ pinos_client_node_new (PinosClient *client, &impl->proxy.node, NULL, properties); + if (this->node == NULL) + goto error_no_node; impl->proxy.pnode = this->node; @@ -1264,12 +1269,21 @@ pinos_client_node_new (PinosClient *client, client->core->uri.client_node, this, (PinosDestroy) client_node_resource_destroy); - impl->proxy.resource = this->resource; + if (this->resource == NULL) + goto error_no_resource; + impl->proxy.resource = this->resource; this->resource->dispatch_func = client_node_dispatch_func; this->resource->dispatch_data = this; return this; + +error_no_resource: + pinos_node_destroy (this->node); +error_no_node: + proxy_clear (&impl->proxy); + free (impl); + return NULL; } static void diff --git a/pinos/server/client.c b/pinos/server/client.c index c9f634581..119d00fab 100644 --- a/pinos/server/client.c +++ b/pinos/server/client.c @@ -69,6 +69,8 @@ client_bind_func (PinosGlobal *global, global->core->uri.client, global->object, client_unbind_func); + if (resource == NULL) + goto no_mem; resource->dispatch_func = client_dispatch_func; resource->dispatch_data = global; @@ -86,6 +88,12 @@ client_bind_func (PinosGlobal *global, PINOS_MESSAGE_CLIENT_INFO, &m, true); + return; + +no_mem: + pinos_resource_send_error (client->core_resource, + SPA_RESULT_NO_MEMORY, + "no memory"); } /** @@ -105,6 +113,9 @@ pinos_client_new (PinosCore *core, PinosClientImpl *impl; impl = calloc (1, sizeof (PinosClientImpl)); + if (impl == NULL) + return NULL; + pinos_log_debug ("client %p: new", impl); this = &impl->this; diff --git a/pinos/server/command.c b/pinos/server/command.c index 2e359b43f..7661064c8 100644 --- a/pinos/server/command.c +++ b/pinos/server/command.c @@ -68,6 +68,8 @@ parse_command_module_load (const char * line, char ** err) PinosCommandImpl *impl; impl = calloc (1, sizeof (PinosCommandImpl)); + if (impl == NULL) + goto no_mem; impl->func = execute_command_module_load; impl->args = pinos_split_strv (line, whitespace, 3, &impl->n_args); @@ -83,6 +85,9 @@ no_module: asprintf (err, "%s requires a module name", impl->args[0]); pinos_free_strv (impl->args); return NULL; +no_mem: + asprintf (err, "no memory"); + return NULL; } static bool @@ -125,7 +130,7 @@ pinos_command_free (PinosCommand * command) * Returns: The command or %NULL when @err is set. */ PinosCommand * -pinos_command_parse (const char *line, +pinos_command_parse (const char *line, char **err) { PinosCommand *command = NULL; diff --git a/pinos/server/core.c b/pinos/server/core.c index f2c19136f..d1509aa4a 100644 --- a/pinos/server/core.c +++ b/pinos/server/core.c @@ -51,15 +51,19 @@ registry_dispatch_func (void *object, break; if (&global->link == &this->global_list) { - pinos_log_error ("unknown object id %d", m->id); + pinos_resource_send_error (resource, + SPA_RESULT_INVALID_OBJECT_ID, + "unknown object id %u", m->id); return SPA_RESULT_ERROR; } if (global->bind == NULL) { - pinos_log_error ("can't bind object id %d", m->id); + pinos_resource_send_error (resource, + SPA_RESULT_NOT_IMPLEMENTED, + "can't bind object id %d", m->id); return SPA_RESULT_ERROR; } - pinos_log_error ("global %p: bind object id %d", global, m->id); + pinos_log_debug ("global %p: bind object id %d", global, m->id); global->bind (global, client, 0, m->id); break; } @@ -109,6 +113,8 @@ core_dispatch_func (void *object, this->uri.registry, this, destroy_registry_resource); + if (registry_resource == NULL) + goto no_mem; registry_resource->dispatch_func = registry_dispatch_func; registry_resource->dispatch_data = this; @@ -142,6 +148,9 @@ core_dispatch_func (void *object, PinosProperties *props; props = pinos_properties_new (NULL, NULL); + if (props == NULL) + goto no_mem; + for (i = 0; i < m->props->n_items; i++) { pinos_properties_set (props, m->props->items[i].key, m->props->items[i].value); @@ -151,9 +160,13 @@ core_dispatch_func (void *object, m->new_id, m->name, props); + if (node == NULL) + goto no_mem; if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0) { - pinos_log_error ("can't get data fd"); + pinos_resource_send_error (resource, + SPA_RESULT_ERROR, + "can't get data fd"); break; } @@ -170,6 +183,12 @@ core_dispatch_func (void *object, break; } return SPA_RESULT_OK; + +no_mem: + pinos_resource_send_error (resource, + SPA_RESULT_NO_MEMORY, + "no memory"); + return SPA_RESULT_NO_MEMORY; } static void @@ -188,6 +207,8 @@ core_bind_func (PinosGlobal *global, global->core->uri.core, global->object, NULL); + if (resource == NULL) + goto no_mem; resource->dispatch_func = core_dispatch_func; resource->dispatch_data = this; @@ -211,6 +232,10 @@ core_bind_func (PinosGlobal *global, PINOS_MESSAGE_CORE_INFO, &m, true); + return; + +no_mem: + pinos_log_error ("can't create core resource"); } PinosCore * @@ -220,14 +245,19 @@ pinos_core_new (PinosMainLoop *main_loop) PinosCore *this; impl = calloc (1, sizeof (PinosCoreImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; - pinos_uri_init (&this->uri); - - pinos_map_init (&this->objects, 512); - this->data_loop = pinos_data_loop_new (); + if (this->data_loop == NULL) + goto no_data_loop; + this->main_loop = main_loop; + pinos_uri_init (&this->uri); + pinos_map_init (&this->objects, 512); + impl->support[0].uri = SPA_ID_MAP_URI; impl->support[0].data = this->uri.map; impl->support[1].uri = SPA_LOG_URI; @@ -266,6 +296,10 @@ pinos_core_new (PinosMainLoop *main_loop) core_bind_func); return this; + +no_data_loop: + free (impl); + return NULL; } void @@ -292,6 +326,9 @@ pinos_core_add_global (PinosCore *core, PinosMessageNotifyGlobal ng; global = calloc (1, sizeof (PinosGlobal)); + if (global == NULL) + return NULL; + global->core = core; global->type = type; global->version = version; diff --git a/pinos/server/data-loop.c b/pinos/server/data-loop.c index c7eb57479..1a343bf8e 100644 --- a/pinos/server/data-loop.c +++ b/pinos/server/data-loop.c @@ -131,16 +131,26 @@ pinos_data_loop_new (void) PinosDataLoop *this; impl = calloc (1, sizeof (PinosDataLoopImpl)); + if (impl == NULL) + return NULL; + pinos_log_debug ("data-loop %p: new", impl); this = &impl->this; this->loop = pinos_loop_new (); + if (this->loop == NULL) + goto no_loop; + pinos_signal_init (&this->destroy_signal); impl->event = pinos_loop_add_event (this->loop, do_stop, impl); return this; + +no_loop: + free (impl); + return NULL; } void diff --git a/pinos/server/link.c b/pinos/server/link.c index da90e795e..04d9bcbd6 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -49,29 +49,24 @@ typedef struct } PinosLinkImpl; static void -pinos_link_update_state (PinosLink *link, PinosLinkState state) +pinos_link_update_state (PinosLink *link, + PinosLinkState state, + char *error) { if (state != link->state) { - free (link->error); - link->error = NULL; pinos_log_debug ("link %p: update state %s -> %s", link, pinos_link_state_as_string (link->state), pinos_link_state_as_string (state)); + link->state = state; + if (link->error) + free (link->error); + link->error = error; + pinos_signal_emit (&link->core->link_state_changed, link); } } -static void -pinos_link_report_error (PinosLink *link, char *error) -{ - free (link->error); - link->error = error; - link->state = PINOS_LINK_STATE_ERROR; - pinos_log_debug ("link %p: got error state %s", link, error); - pinos_signal_emit (&link->core->link_state_changed, link); -} - static SpaResult do_negotiate (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) { @@ -83,7 +78,7 @@ do_negotiate (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) if (in_state != SPA_NODE_STATE_CONFIGURE && out_state != SPA_NODE_STATE_CONFIGURE) return SPA_RESULT_OK; - pinos_link_update_state (this, PINOS_LINK_STATE_NEGOTIATING); + pinos_link_update_state (this, PINOS_LINK_STATE_NEGOTIATING, NULL); /* both ports need a format */ if (in_state == SPA_NODE_STATE_CONFIGURE && out_state == SPA_NODE_STATE_CONFIGURE) { @@ -170,7 +165,7 @@ again: error: { - pinos_link_report_error (this, error); + pinos_link_update_state (this, PINOS_LINK_STATE_ERROR, error); return res; } } @@ -352,7 +347,7 @@ do_allocation (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) if (in_state != SPA_NODE_STATE_READY && out_state != SPA_NODE_STATE_READY) return SPA_RESULT_OK; - pinos_link_update_state (this, PINOS_LINK_STATE_ALLOCATING); + pinos_link_update_state (this, PINOS_LINK_STATE_ALLOCATING, NULL); pinos_log_debug ("link %p: doing alloc buffers %p %p", this, this->output->node, this->input->node); /* find out what's possible */ @@ -552,7 +547,7 @@ error: this->input->buffers = NULL; this->input->n_buffers = 0; this->input->allocated = false; - pinos_link_report_error (this, error); + pinos_link_update_state (this, PINOS_LINK_STATE_ERROR, error); return res; } } @@ -565,9 +560,9 @@ do_start (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) if (in_state < SPA_NODE_STATE_PAUSED || out_state < SPA_NODE_STATE_PAUSED) return SPA_RESULT_OK; else if (in_state == SPA_NODE_STATE_STREAMING && out_state == SPA_NODE_STATE_STREAMING) { - pinos_link_update_state (this, PINOS_LINK_STATE_RUNNING); + pinos_link_update_state (this, PINOS_LINK_STATE_RUNNING, NULL); } else { - pinos_link_update_state (this, PINOS_LINK_STATE_PAUSED); + pinos_link_update_state (this, PINOS_LINK_STATE_PAUSED, NULL); if (in_state == SPA_NODE_STATE_PAUSED) { res = pinos_node_set_state (this->input->node, PINOS_NODE_STATE_RUNNING); @@ -587,9 +582,16 @@ check_states (PinosLink *this, SpaNodeState in_state, out_state; again: + if (this->state == PINOS_LINK_STATE_ERROR) + return SPA_RESULT_ERROR; + if (this->input == NULL || this->output == NULL) return SPA_RESULT_OK; + if (this->input->node->state == PINOS_NODE_STATE_ERROR || + this->output->node->state == PINOS_NODE_STATE_ERROR) + return SPA_RESULT_ERROR; + in_state = this->input->node->node->state; out_state = this->output->node->node->state; @@ -652,7 +654,7 @@ on_port_unlinked (PinosPort *port, PinosLink *this, SpaResult res, uint32_t id) pinos_signal_emit (&this->core->port_unlinked, this, port); if (this->input == NULL || this->output == NULL) { - pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED); + pinos_link_update_state (this, PINOS_LINK_STATE_UNLINKED, NULL); pinos_link_destroy (this); } @@ -719,7 +721,11 @@ bool pinos_link_activate (PinosLink *this) { spa_ringbuffer_init (&this->ringbuffer, SPA_N_ELEMENTS (this->queue)); - check_states (this, NULL, SPA_RESULT_OK); + pinos_main_loop_defer (this->core->main_loop, + this, + SPA_RESULT_WAIT_SYNC, + (PinosDeferFunc) check_states, + this); return true; } @@ -766,6 +772,8 @@ link_bind_func (PinosGlobal *global, global->core->uri.link, global->object, link_unbind_func); + if (resource == NULL) + goto no_mem; resource->dispatch_func = link_dispatch_func; resource->dispatch_data = global; @@ -785,6 +793,12 @@ link_bind_func (PinosGlobal *global, PINOS_MESSAGE_LINK_INFO, &m, true); + return; + +no_mem: + pinos_resource_send_error (client->core_resource, + SPA_RESULT_NO_MEMORY, + "no memory"); } PinosLink * @@ -798,6 +812,9 @@ pinos_link_new (PinosCore *core, PinosLink *this; impl = calloc (1, sizeof (PinosLinkImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; pinos_log_debug ("link %p: new", this); diff --git a/pinos/server/main-loop.c b/pinos/server/main-loop.c index 402fb8d67..b4920cbf2 100644 --- a/pinos/server/main-loop.c +++ b/pinos/server/main-loop.c @@ -97,6 +97,8 @@ main_loop_defer (PinosMainLoop *loop, spa_list_remove (&item->link); } else { item = malloc (sizeof (WorkItem)); + if (item == NULL) + return SPA_ID_INVALID; } item->id = ++impl->counter; item->obj = obj; @@ -189,10 +191,15 @@ pinos_main_loop_new (void) PinosMainLoop *this; impl = calloc (1, sizeof (PinosMainLoopImpl)); + if (impl == NULL) + return NULL; + pinos_log_debug ("main-loop %p: new", impl); this = &impl->this; this->loop = pinos_loop_new (); + if (this->loop == NULL) + goto no_loop; pinos_signal_init (&this->destroy_signal); @@ -208,6 +215,10 @@ pinos_main_loop_new (void) spa_list_init (&impl->free_list); return this; + +no_loop: + free (impl); + return NULL; } void diff --git a/pinos/server/module.c b/pinos/server/module.c index 9316842fe..f512a1437 100644 --- a/pinos/server/module.c +++ b/pinos/server/module.c @@ -123,6 +123,8 @@ module_bind_func (PinosGlobal *global, global->core->uri.module, global->object, NULL); + if (resource == NULL) + goto no_mem; resource->dispatch_func = module_dispatch_func; resource->dispatch_data = global; @@ -141,6 +143,12 @@ module_bind_func (PinosGlobal *global, PINOS_MESSAGE_MODULE_INFO, &m, true); + return; + +no_mem: + pinos_resource_send_error (resource, + SPA_RESULT_NO_MEMORY, + "no memory"); } /** @@ -201,6 +209,9 @@ pinos_module_load (PinosCore *core, goto no_pinos_module; impl = calloc (1, sizeof (PinosModuleImpl)); + if (impl == NULL) + goto no_mem; + impl->hnd = hnd; this = &impl->this; @@ -229,10 +240,11 @@ not_found: } open_failed: { - asprintf (err, "Failed to open module: %s", dlerror ()); + asprintf (err, "Failed to open module: \"%s\" %s", filename, dlerror ()); free (filename); return NULL; } +no_mem: no_pinos_module: { asprintf (err, "\"%s\" is not a pinos module", name); diff --git a/pinos/server/node.c b/pinos/server/node.c index b4005c74a..9287b7014 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -422,6 +422,8 @@ node_bind_func (PinosGlobal *global, global->core->uri.registry, global->object, node_unbind_func); + if (resource == NULL) + goto no_mem; resource->dispatch_func = node_dispatch_func; resource->dispatch_data = global; @@ -435,12 +437,19 @@ node_bind_func (PinosGlobal *global, info.change_mask = ~0; info.name = this->name; info.state = this->state; + info.error = this->error; info.props = this->properties ? &this->properties->dict : NULL; pinos_resource_send_message (resource, PINOS_MESSAGE_NODE_INFO, &m, true); + return; + +no_mem: + pinos_resource_send_error (resource, + SPA_RESULT_NO_MEMORY, + "no memory"); } static void @@ -482,6 +491,9 @@ pinos_node_new (PinosCore *core, PinosNode *this; impl = calloc (1, sizeof (PinosNodeImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; this->core = core; pinos_log_debug ("node %p: new", this); @@ -514,6 +526,9 @@ pinos_node_new (PinosCore *core, if (this->properties == NULL) this->properties = pinos_properties_new (NULL, NULL); + if (this->properties) + goto no_mem; + for (i = 0; i < this->node->info->n_items; i++) pinos_properties_set (this->properties, this->node->info->items[i].key, @@ -532,6 +547,11 @@ pinos_node_new (PinosCore *core, } return this; + +no_mem: + free (this->name); + free (impl); + return NULL; } static SpaResult @@ -814,6 +834,7 @@ pinos_node_update_state (PinosNode *node, m.info = &info; info.change_mask = 1 << 1; info.state = node->state; + info.error = node->error; spa_list_for_each (resource, &node->resource_list, link) { info.id = node->global->id; diff --git a/pinos/server/port.c b/pinos/server/port.c index fe3ec16c1..9b1953c25 100644 --- a/pinos/server/port.c +++ b/pinos/server/port.c @@ -41,6 +41,9 @@ pinos_port_new (PinosNode *node, PinosPort *this; impl = calloc (1, sizeof (PinosPortImpl)); + if (impl == NULL) + return NULL; + this = &impl->this; this->node = node; this->direction = direction; @@ -177,6 +180,8 @@ pinos_port_link (PinosPort *output_port, input_port, format_filter, properties); + if (link == NULL) + goto no_mem; spa_list_insert (output_port->links.prev, &link->output_link); spa_list_insert (input_port->links.prev, &link->input_link); @@ -209,6 +214,8 @@ was_linked: asprintf (error, "input port was already linked"); return NULL; } +no_mem: + return NULL; } static SpaResult diff --git a/pinos/server/resource.c b/pinos/server/resource.c index b15ff1ba0..90546c3c1 100644 --- a/pinos/server/resource.c +++ b/pinos/server/resource.c @@ -31,6 +31,9 @@ pinos_resource_new (PinosClient *client, PinosResource *this; this = calloc (1, sizeof (PinosResource)); + if (this == NULL) + return NULL; + this->core = client->core; this->client = client; this->id = id; @@ -95,15 +98,42 @@ pinos_resource_send_message (PinosResource *resource, void *message, bool flush) { - if (resource->send_func) - return resource->send_func (resource, - resource->id, - opcode, - message, - flush, - resource->send_data); + if (!resource->send_func) { + pinos_log_error ("resource %p: send func not implemented", resource); + return SPA_RESULT_NOT_IMPLEMENTED; + } - 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); +} + +SpaResult +pinos_resource_send_error (PinosResource *resource, + SpaResult res, + const char *message, + ...) +{ + PinosClient *client = resource->client; + PinosMessageError m; + char buffer[128]; + va_list ap; + + va_start (ap, message); + vsnprintf (buffer, sizeof (buffer), message, ap); + va_end (ap); + + m.id = resource->id; + m.res = res; + m.error = buffer; + + pinos_log_error ("resource %p: %u send error %d %s", resource, resource->id, res, buffer); + + return pinos_resource_send_message (client->core_resource, + PINOS_MESSAGE_ERROR, + &m, + true); } diff --git a/pinos/server/resource.h b/pinos/server/resource.h index 7cbe929ea..3188e40c6 100644 --- a/pinos/server/resource.h +++ b/pinos/server/resource.h @@ -76,6 +76,9 @@ SpaResult pinos_resource_send_message (PinosResource *resource, uint32_t opcode, void *message, bool flush); +SpaResult pinos_resource_send_error (PinosResource *resource, + SpaResult res, + const char *message, ...); #ifdef __cplusplus } diff --git a/pinos/tools/pinos-monitor.c b/pinos/tools/pinos-monitor.c index 93d6a4f94..2f2b7377b 100644 --- a/pinos/tools/pinos-monitor.c +++ b/pinos/tools/pinos-monitor.c @@ -28,6 +28,7 @@ typedef struct { PinosContext *context; PinosListener on_state_changed; + PinosListener on_subscription; } Data; static void @@ -110,7 +111,11 @@ dump_node_info (PinosContext *c, printf ("\ttype: %s\n", PINOS_NODE_URI); if (data->print_all) { printf ("%c\tname: \"%s\"\n", MARK_CHANGE (0), info->name); - printf ("%c\tstate: \"%s\"\n", MARK_CHANGE (1), pinos_node_state_as_string (info->state)); + printf ("%c\tstate: \"%s\"", MARK_CHANGE (1), pinos_node_state_as_string (info->state)); + if (info->state == PINOS_NODE_STATE_ERROR && info->error) + printf (" \"%s\"\n", info->error); + else + printf ("\n"); print_properties (info->props, MARK_CHANGE (2)); } } @@ -202,11 +207,11 @@ dump_object (PinosContext *context, } static void -subscription_cb (PinosContext *context, +on_subscription (PinosListener *listener, + PinosContext *context, PinosSubscriptionEvent event, uint32_t type, - uint32_t id, - void *data) + uint32_t id) { DumpData dd; @@ -267,9 +272,9 @@ main (int argc, char *argv[]) &data.on_state_changed, on_state_changed); - pinos_context_subscribe (data.context, - subscription_cb, - &data); + pinos_signal_add (&data.context->subscription, + &data.on_subscription, + on_subscription); pinos_context_connect (data.context); diff --git a/spa/include/spa/defs.h b/spa/include/spa/defs.h index 6ca35367e..8bee714a1 100644 --- a/spa/include/spa/defs.h +++ b/spa/include/spa/defs.h @@ -66,6 +66,7 @@ typedef enum { SPA_RESULT_WRONG_STATE = -29, SPA_RESULT_ASYNC_BUSY = -30, SPA_RESULT_INVALID_OBJECT_ID = -31, + SPA_RESULT_NO_MEMORY = -32, } SpaResult; #define SPA_ASYNC_MASK (3 << 30)