From 5f10a933a175c6aecfb2cf96e515261b4ad39786 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 18 May 2016 17:22:34 +0200 Subject: [PATCH] remove client object Remove the client object, it is not very useful now that we have the nodes. Fix some properties on the proxy objects. Use sendmsg and recvmsg directly because the GIO ones do allocations. make pinos_properties_merge and use it to combine properties from nodes and ports. --- pinos/Makefile.am | 1 - pinos/client/client-node.c | 42 +++- pinos/client/client-node.h | 3 + pinos/client/context.c | 163 ++------------ pinos/client/context.h | 1 + pinos/client/introspect.c | 109 +-------- pinos/client/introspect.h | 58 +---- pinos/client/port.c | 188 ++++++++-------- pinos/client/private.h | 2 - pinos/client/properties.c | 27 +++ pinos/client/properties.h | 2 + pinos/client/stream.c | 1 + pinos/client/subscribe.c | 3 - pinos/client/subscribe.h | 7 +- pinos/dbus/org.pinos.xml | 52 +---- pinos/server/client.c | 432 ------------------------------------ pinos/server/client.h | 74 ------ pinos/server/daemon.c | 123 +++++++--- pinos/server/daemon.h | 1 + pinos/server/server-node.c | 14 +- pinos/server/server-port.c | 2 - pinos/tools/pinos-monitor.c | 23 +- 22 files changed, 298 insertions(+), 1030 deletions(-) delete mode 100644 pinos/server/client.c delete mode 100644 pinos/server/client.h diff --git a/pinos/Makefile.am b/pinos/Makefile.am index 88ffdf52e..0b76adf1c 100644 --- a/pinos/Makefile.am +++ b/pinos/Makefile.am @@ -211,7 +211,6 @@ lib_LTLIBRARIES += libpinoscore-@PINOS_MAJORMINOR@.la # Pure core stuff libpinoscore_@PINOS_MAJORMINOR@_la_SOURCES = \ - server/client.c server/client.h \ server/daemon.c server/daemon.h \ server/server-node.c server/server-node.h \ server/server-port.c server/server-port.h \ diff --git a/pinos/client/client-node.c b/pinos/client/client-node.c index 553eab527..b91db0466 100644 --- a/pinos/client/client-node.c +++ b/pinos/client/client-node.c @@ -205,7 +205,7 @@ client_node_create_port (PinosNode *node, data->direction = direction; data->name = g_strdup (name); data->possible_formats = possible_formats ? g_bytes_ref (possible_formats) : NULL; - data->properties = properties ? pinos_properties_copy (properties) : NULL; + data->properties = pinos_properties_merge (pinos_node_get_properties (node), properties); g_task_set_task_data (task, data, (GDestroyNotify) create_port_data_free); @@ -365,3 +365,43 @@ pinos_client_node_get_context (PinosClientNode *node) return priv->context; } + +/** + * pinos_client_port_new: + * @node: a #PinosClientNode + * @id: an id + * @socket: a socket with the server port + * + * Create a new client port. + * + * Returns: a new client port + */ +PinosClientNode * +pinos_client_node_new (PinosContext *context, + gpointer id) +{ + PinosClientNode *node; + GDBusProxy *proxy = id; + GVariant *variant; + PinosProperties *properties = NULL; + const gchar *name = NULL; + + variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "Name"); + if (variant != NULL) { + name = g_variant_get_string (variant, NULL); + g_variant_unref (variant); + } + variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "Properties"); + if (variant != NULL) { + properties = pinos_properties_from_variant (variant); + g_variant_unref (variant); + } + + node = g_object_new (PINOS_TYPE_CLIENT_NODE, + "context", context, + "proxy", proxy, + "name", name, + "properties", properties, + NULL); + return node; +} diff --git a/pinos/client/client-node.h b/pinos/client/client-node.h index d18172341..5ef7de986 100644 --- a/pinos/client/client-node.h +++ b/pinos/client/client-node.h @@ -64,6 +64,9 @@ struct _PinosClientNodeClass { /* normal GObject stuff */ GType pinos_client_node_get_type (void); +PinosClientNode * pinos_client_node_new (PinosContext *context, + gpointer id); + PinosContext * pinos_client_node_get_context (PinosClientNode *node); G_END_DECLS diff --git a/pinos/client/context.c b/pinos/client/context.c index b018075fe..40eafe325 100644 --- a/pinos/client/context.c +++ b/pinos/client/context.c @@ -150,7 +150,6 @@ pinos_context_finalize (GObject * object) g_list_free (priv->nodes); g_list_free (priv->ports); - g_list_free (priv->clients); g_clear_object (&priv->subscribe); g_clear_error (&priv->error); @@ -377,62 +376,6 @@ context_set_state (PinosContext *context, g_error_free (error); } } -static void -on_client_proxy (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - GError *error = NULL; - - priv->client = pinos_subscribe_get_proxy_finish (priv->subscribe, - res, - &error); - if (priv->client == NULL) - goto client_failed; - - context_set_state (context, PINOS_CONTEXT_STATE_READY, NULL); - - return; - -client_failed: - { - g_warning ("failed to get client proxy: %s", error->message); - context_set_state (context, PINOS_STREAM_STATE_ERROR, error); - return; - } -} - -static void -on_client_connected (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - GVariant *ret; - GError *error = NULL; - const gchar *client_path; - - ret = g_dbus_proxy_call_finish (priv->daemon, res, &error); - if (ret == NULL) { - g_warning ("failed to connect client: %s", error->message); - context_set_state (context, PINOS_CONTEXT_STATE_ERROR, error); - return; - } - - g_variant_get (ret, "(&o)", &client_path); - - pinos_subscribe_get_proxy (priv->subscribe, - PINOS_DBUS_SERVICE, - client_path, - "org.pinos.Client1", - NULL, - on_client_proxy, - context); - g_variant_unref (ret); -} static void on_daemon_connected (GObject *source_object, @@ -440,21 +383,9 @@ on_daemon_connected (GObject *source_object, gpointer user_data) { PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - GVariant *variant; context_set_state (context, PINOS_CONTEXT_STATE_REGISTERING, NULL); - - variant = pinos_properties_to_variant (priv->properties); - - g_dbus_proxy_call (priv->daemon, - "ConnectClient", - g_variant_new ("(@a{sv})", variant), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - on_client_connected, - context); + context_set_state (context, PINOS_CONTEXT_STATE_READY, NULL); } static void @@ -472,22 +403,6 @@ subscription_cb (PinosSubscribe *subscribe, priv->daemon = g_object_ref (object); break; - case PINOS_SUBSCRIPTION_FLAG_CLIENT: - if (event == PINOS_SUBSCRIPTION_EVENT_NEW) { - priv->clients = g_list_prepend (priv->clients, object); - } else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) { - priv->clients = g_list_remove (priv->clients, object); - - if (object == priv->client && !priv->disconnecting) { - context_set_state (context, - PINOS_CONTEXT_STATE_ERROR, - g_error_new_literal (G_IO_ERROR, - G_IO_ERROR_CLOSED, - "Client disappeared")); - } - } - break; - case PINOS_SUBSCRIPTION_FLAG_NODE: if (event == PINOS_SUBSCRIPTION_EVENT_NEW) priv->nodes = g_list_prepend (priv->nodes, object); @@ -628,62 +543,18 @@ pinos_context_connect (PinosContext *context, } static void -finish_client_disconnect (PinosContext *context) +do_disconnect (PinosContext *context) { PinosContextPrivate *priv = context->priv; - g_clear_object (&priv->client); g_clear_object (&priv->daemon); if (priv->id) { g_bus_unwatch_name(priv->id); priv->id = 0; } - context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL); } -static void -on_client_disconnected (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - GError *error = NULL; - GVariant *ret; - - priv->disconnecting = FALSE; - - ret = g_dbus_proxy_call_finish (priv->client, res, &error); - if (ret == NULL) { - g_warning ("failed to disconnect client: %s", error->message); - context_set_state (context, PINOS_CONTEXT_STATE_ERROR, error); - g_object_unref (context); - return; - } - g_variant_unref (ret); - - finish_client_disconnect (context); - g_object_unref (context); -} - -static gboolean -do_disconnect (PinosContext *context) -{ - PinosContextPrivate *priv = context->priv; - - g_dbus_proxy_call (priv->client, - "Disconnect", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - on_client_disconnected, - context); - - return FALSE; -} - /** * pinos_context_disconnect: * @context: a #PinosContext @@ -702,11 +573,6 @@ pinos_context_disconnect (PinosContext *context) priv = context->priv; g_return_val_if_fail (!priv->disconnecting, FALSE); - if (priv->client == NULL) { - finish_client_disconnect (context); - return TRUE; - } - priv->disconnecting = TRUE; g_main_context_invoke (priv->context, @@ -756,6 +622,7 @@ pinos_context_get_error (PinosContext *context) } typedef struct { + gchar *factory_name; gchar *name; PinosProperties *properties; } CreateNodeData; @@ -763,6 +630,7 @@ typedef struct { static void create_node_data_free (CreateNodeData *data) { + g_free (data->factory_name); g_free (data->name); if (data->properties) pinos_properties_free (data->properties); @@ -786,10 +654,7 @@ on_node_proxy (GObject *source_object, if (proxy == NULL) goto node_failed; - node = g_object_new (PINOS_TYPE_CLIENT_NODE, - "context", context, - "proxy", proxy, - NULL); + node = pinos_client_node_new (context, proxy); g_task_return_pointer (task, node, (GDestroyNotify) g_object_unref); g_object_unref (task); @@ -805,7 +670,6 @@ node_failed: } } - static void on_node_created (GObject *source_object, GAsyncResult *res, @@ -817,9 +681,9 @@ on_node_created (GObject *source_object, GError *error = NULL; const gchar *node_path; - g_assert (context->priv->client == G_DBUS_PROXY (source_object)); + g_assert (context->priv->daemon == G_DBUS_PROXY (source_object)); - ret = g_dbus_proxy_call_finish (context->priv->client, res, &error); + ret = g_dbus_proxy_call_finish (context->priv->daemon, res, &error); if (ret == NULL) goto create_failed; @@ -853,10 +717,11 @@ do_create_node (GTask *task) PinosContext *context = g_task_get_source_object (task); CreateNodeData *data = g_task_get_task_data (task); - g_dbus_proxy_call (context->priv->client, + g_dbus_proxy_call (context->priv->daemon, "CreateNode", - g_variant_new ("(s@a{sv})", - "client-node", + g_variant_new ("(ss@a{sv})", + data->factory_name, + data->name, pinos_properties_to_variant (data->properties)), G_DBUS_CALL_FLAGS_NONE, -1, @@ -879,16 +744,19 @@ do_create_node (GTask *task) */ void pinos_context_create_node (PinosContext *context, + const gchar *factory_name, const gchar *name, PinosProperties *properties, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { + PinosContextPrivate *priv; GTask *task; CreateNodeData *data; g_return_if_fail (PINOS_IS_CONTEXT (context)); + priv = context->priv; task = g_task_new (context, cancellable, @@ -896,8 +764,9 @@ pinos_context_create_node (PinosContext *context, user_data); data = g_slice_new (CreateNodeData); + data->factory_name = g_strdup (factory_name); data->name = g_strdup (name); - data->properties = properties ? pinos_properties_copy (properties) : NULL; + data->properties = pinos_properties_merge (priv->properties, properties); g_task_set_task_data (task, data, (GDestroyNotify) create_node_data_free); diff --git a/pinos/client/context.h b/pinos/client/context.h index 85c8f88b2..83ff7c65c 100644 --- a/pinos/client/context.h +++ b/pinos/client/context.h @@ -109,6 +109,7 @@ gboolean pinos_context_connect (PinosContext *context, Pi gboolean pinos_context_disconnect (PinosContext *context); void pinos_context_create_node (PinosContext *context, + const gchar *factory_name, const gchar *name, PinosProperties *properties, GCancellable *cancellable, diff --git a/pinos/client/introspect.c b/pinos/client/introspect.c index 041f3bc2e..06df2f0e6 100644 --- a/pinos/client/introspect.c +++ b/pinos/client/introspect.c @@ -165,114 +165,6 @@ pinos_context_get_daemon_info (PinosContext *context, g_object_unref (task); } -static void -client_fill_info (PinosClientInfo *info, GDBusProxy *proxy) -{ - GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - info->id = proxy; - info->client_path = g_dbus_proxy_get_object_path (proxy); - SET_STRING ("Sender", sender, 0); - - info->change_mask = 0; - SET_PROPERTIES ("Properties", properties, 0); - - if (changed) - g_hash_table_remove_all (changed); -} - -static void -client_clear_info (PinosClientInfo *info) -{ - if (info->properties) - pinos_properties_free (info->properties); -} - - -/** - * pinos_context_list_client_info: - * @context: a connected #PinosContext - * @flags: extra #PinosClientInfoFlags - * @cb: a #PinosClientInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for each client. - */ -void -pinos_context_list_client_info (PinosContext *context, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosContextPrivate *priv; - GList *walk; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - priv = context->priv; - - for (walk = priv->clients; walk; walk = g_list_next (walk)) { - GDBusProxy *proxy = walk->data; - PinosClientInfo info; - - client_fill_info (&info, proxy); - cb (context, &info, user_data); - client_clear_info (&info); - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/** - * pinos_context_get_client_info_by_id: - * @context: a connected #PinosContext - * @id: a client id - * @flags: extra #PinosClientInfoFlags - * @cb: a #PinosClientInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for the client with @id. - */ -void -pinos_context_get_client_info_by_id (PinosContext *context, - gpointer id, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosClientInfo info; - GDBusProxy *proxy; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (id != NULL); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - proxy = G_DBUS_PROXY (id); - - client_fill_info (&info, proxy); - cb (context, &info, user_data); - client_clear_info (&info); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - /** * pinos_node_state_as_string: * @state: a #PinosNodeeState @@ -299,6 +191,7 @@ node_fill_info (PinosNodeInfo *info, GDBusProxy *proxy) info->id = proxy; info->node_path = g_dbus_proxy_get_object_path (proxy); + SET_STRING ("Owner", owner, 0); info->change_mask = 0; SET_STRING ("Name", name, 0); diff --git a/pinos/client/introspect.h b/pinos/client/introspect.h index 04fb5f4ac..0a32cf02b 100644 --- a/pinos/client/introspect.h +++ b/pinos/client/introspect.h @@ -144,66 +144,11 @@ void pinos_context_get_daemon_info (PinosContext *context, GAsyncReadyCallback callback, gpointer user_data); -/** - * PinosClientInfo: - * @id: generic id of the client - * @client_path: unique path of the client - * @sender: sender of client - * @change_mask: bitfield of changed fields since last call - * @properties: extra properties - * - * The client information. Extra information can be added in later - * versions. - */ -typedef struct { - gpointer id; - const char *client_path; - const char *sender; - guint64 change_mask; - PinosProperties *properties; -} PinosClientInfo; - -/** - * PinosClientInfoFlags: - * @PINOS_CLIENT_INFO_FLAGS_NONE: no flags - * - * Extra flags for pinos_context_list_client_info() and - * pinos_context_get_client_info_by_id(). - */ -typedef enum { - PINOS_CLIENT_INFO_FLAGS_NONE = 0, -} PinosClientInfoFlags; - -/** - * PinosClientInfoCallback: - * @c: a #PinosContext - * @info: a #PinosClientInfo - * @user_data: user data - * - * Callback with information about the Pinos client in @info. - */ -typedef void (*PinosClientInfoCallback) (PinosContext *c, - const PinosClientInfo *info, - gpointer user_data); - -void pinos_context_list_client_info (PinosContext *context, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -void pinos_context_get_client_info_by_id (PinosContext *context, - gpointer id, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); - /** * PinosNodeInfo: * @id: generic id of the node * @node_path: the unique path of the node + * @owner: the unique name of the owner * @change_mask: bitfield of changed fields since last call * @name: name the node, suitable for display * @properties: the properties of the node @@ -215,6 +160,7 @@ void pinos_context_get_client_info_by_id (PinosContext *context, typedef struct { gpointer id; const char *node_path; + const char *owner; guint64 change_mask; const char *name; PinosProperties *properties; diff --git a/pinos/client/port.c b/pinos/client/port.c index 6d2b4af53..52b5f64be 100644 --- a/pinos/client/port.c +++ b/pinos/client/port.c @@ -56,14 +56,16 @@ struct _PinosPortPrivate GBytes *format; PinosProperties *properties; + int fd; GSource *socket_source; PinosBuffer recv_buffer; + guint8 recv_data[MAX_BUFFER_SIZE]; - gint recv_fds[MAX_FDS]; + int recv_fds[MAX_FDS]; guint8 send_data[MAX_BUFFER_SIZE]; - gint send_fds[MAX_FDS]; + int send_fds[MAX_FDS]; PinosBuffer *buffer; PinosPort *peers[16]; @@ -463,14 +465,13 @@ read_buffer (PinosPort *port, { PinosPortPrivate *priv = port->priv; gssize len; - GInputVector ivec; PinosStackHeader *hdr; - GSocketControlMessage **messages = NULL; PinosStackBuffer *sb = (PinosStackBuffer *) &priv->recv_buffer; - gint num_messages = 0; - gint flags = 0; gsize need; - gint i; + struct cmsghdr *cmsg; + struct msghdr msg = {0}; + struct iovec iov[1]; + char cmsgbuf[CMSG_SPACE (MAX_FDS * sizeof (int))]; g_assert (sb->refcount == 0); @@ -479,28 +480,31 @@ read_buffer (PinosPort *port, sb->size = 0; sb->free_data = NULL; sb->fds = priv->recv_fds; - sb->max_fds = MAX_FDS; + sb->max_fds = 0; sb->n_fds = 0; sb->free_fds = NULL; hdr = sb->data; - /* read header first */ - ivec.buffer = hdr; - ivec.size = sizeof (PinosStackHeader); - - len = g_socket_receive_message (priv->sockets[0], - NULL, - &ivec, - 1, - &messages, - &num_messages, - &flags, - NULL, - error); - if (len == -1) - return NULL; + /* read header and control messages first */ + iov[0].iov_base = hdr; + iov[0].iov_len = sizeof (PinosStackHeader);; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof (cmsgbuf); + msg.msg_flags = MSG_CMSG_CLOEXEC; + while (TRUE) { + len = recvmsg (priv->fd, &msg, msg.msg_flags); + if (len < 0) { + if (errno == EINTR) + continue; + else + goto recv_error; + } + break; + } g_assert (len == sizeof (PinosStackHeader)); /* now we know the total length */ @@ -515,103 +519,94 @@ read_buffer (PinosPort *port, if (hdr->length > 0) { /* read data */ - len = g_socket_receive (priv->sockets[0], - (gchar *)sb->data + sizeof (PinosStackHeader), - hdr->length, - NULL, - error); - if (len == -1) - return NULL; - + while (TRUE) { + len = recv (priv->fd, (gchar *)sb->data + sizeof (PinosStackHeader), hdr->length, 0); + if (len < 0) { + if (errno == EINTR) + continue; + else + goto recv_error; + } + break; + } g_assert (len == hdr->length); } - if (sb->max_fds < num_messages) { - g_warning ("port %p: realloc receive fds %d -> %d", port, sb->max_fds, num_messages); - sb->max_fds = num_messages; - sb->fds = sb->free_fds = g_realloc (sb->free_fds, num_messages * sizeof (int)); - } - /* handle control messages */ - for (i = 0; i < num_messages; i++) { - GSocketControlMessage *msg = messages[i]; - gint *fds, n_fds, j; - - if (g_socket_control_message_get_msg_type (msg) != SCM_RIGHTS) + for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg)) { + if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; - fds = g_unix_fd_message_steal_fds (G_UNIX_FD_MESSAGE (msg), &n_fds); - for (j = 0; j < n_fds; j++) - sb->fds[i] = fds[i]; - sb->n_fds = n_fds; - g_free (fds); - g_object_unref (msg); + sb->n_fds = (cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg)) / sizeof (int); + memcpy (sb->fds, CMSG_DATA (cmsg), sb->n_fds * sizeof (int)); } - g_free (messages); - sb->refcount = 1; sb->magic = PSB_MAGIC; PINOS_DEBUG_TRANSPORT ("port %p: buffer %p init", &priv->recv_buffer, sb); return &priv->recv_buffer; + + /* ERRORS */ +recv_error: + { + g_set_error (error, + G_IO_ERROR, + g_io_error_from_errno (errno), + "could not recvmsg: %s", strerror (errno)); + return NULL; + } } static gboolean -write_buffer (GSocket *socket, +write_buffer (PinosPort *port, PinosBuffer *buffer, GError **error) { - gssize len; + PinosPortPrivate *priv = port->priv; PinosStackBuffer *sb = (PinosStackBuffer *) buffer; - GOutputVector ovec[1]; - GSocketControlMessage *msg = NULL; - gint n_msg, i, flags = 0; + gssize len; + struct msghdr msg = {0}; + struct iovec iov[1]; + struct cmsghdr *cmsg; + char cmsgbuf[CMSG_SPACE (MAX_FDS * sizeof (int))]; + gint fds_len = sb->n_fds * sizeof (int); - g_return_val_if_fail (buffer != NULL, FALSE); + iov[0].iov_base = sb->data; + iov[0].iov_len = sb->size; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = CMSG_SPACE (fds_len); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN (fds_len); + memcpy(CMSG_DATA(cmsg), sb->fds, fds_len); + msg.msg_controllen = cmsg->cmsg_len; - ovec[0].buffer = sb->data; - ovec[0].size = sb->size; - - if (sb->n_fds) { - msg = g_unix_fd_message_new (); - for (i = 0; i < sb->n_fds; i++) { - if (!g_unix_fd_message_append_fd (G_UNIX_FD_MESSAGE (msg), sb->fds[i], error)) - goto append_failed; + while (TRUE) { + len = sendmsg (priv->fd, &msg, 0); + if (len < 0) { + if (errno == EINTR) + continue; + else + goto send_error; } - n_msg = 1; + break; } - else { - n_msg = 0; - } - - len = g_socket_send_message (socket, - NULL, - ovec, - 1, - &msg, - n_msg, - flags, - NULL, - error); - g_clear_object (&msg); - - if (len == -1) - goto send_error; - g_assert (len == (gssize) sb->size); return TRUE; -append_failed: - { - g_warning ("failed to append fd: %s", error ? (*error)->message : "unknown reason" ); - return FALSE; - } + /* ERRORS */ send_error: { - g_warning ("failed to send message: %s", error ? (*error)->message : "unknown reason" ); + g_set_error (error, + G_IO_ERROR, + g_io_error_from_errno (errno), + "could not sendmsg: %s", strerror (errno)); return FALSE; } } @@ -661,7 +656,7 @@ pinos_port_receive_buffer (PinosPort *port, if (priv->sockets[0]) { PINOS_DEBUG_TRANSPORT ("port %p: write buffer %p", port, buffer); - res = write_buffer (priv->sockets[0], buffer, error); + res = write_buffer (port, buffer, error); } else { res = TRUE; @@ -750,6 +745,7 @@ handle_socket (PinosPort *port, GSocket *socket) GMainContext *context = g_main_context_get_thread_default(); g_debug ("port %p: handle socket in context %p", port, context); + priv->fd = g_socket_get_fd (socket); priv->socket_source = g_socket_create_source (socket, G_IO_IN, NULL); g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, port, NULL); g_source_attach (priv->socket_source, context); @@ -764,6 +760,7 @@ unhandle_socket (PinosPort *port) if (priv->socket_source) { g_source_destroy (priv->socket_source); g_clear_pointer (&priv->socket_source, g_source_unref); + priv->fd = -1; } } @@ -819,6 +816,7 @@ pinos_port_send_buffer (PinosPort *port, PinosPort *peer; gboolean res = TRUE; gint i; + GError *err = NULL; g_return_val_if_fail (PINOS_IS_PORT (port), FALSE); priv = port->priv; @@ -829,14 +827,20 @@ pinos_port_send_buffer (PinosPort *port, PINOS_DEBUG_TRANSPORT ("port %p: send buffer %p", port, buffer); if (priv->sockets[0]) { PINOS_DEBUG_TRANSPORT ("port %p: write buffer %p", port, buffer); - res = write_buffer (priv->sockets[0], buffer, error); + res = write_buffer (port, buffer, &err); } for (i = 0; i < priv->n_peers; i++) { peer = priv->peers[i]; if (peer == NULL) continue; - res = pinos_port_receive_buffer (peer, buffer, error); + res = pinos_port_receive_buffer (peer, buffer, &err); } + if (!res) { + if (error == NULL) + g_warning ("could not send buffer: %s", err->message); + g_propagate_error (error, err); + } + return res; } diff --git a/pinos/client/private.h b/pinos/client/private.h index 4da5cc7a2..b3456f3cc 100644 --- a/pinos/client/private.h +++ b/pinos/client/private.h @@ -33,13 +33,11 @@ struct _PinosContextPrivate GError *error; GDBusProxy *daemon; - GDBusProxy *client; gboolean disconnecting; PinosSubscriptionFlags subscription_mask; PinosSubscribe *subscribe; - GList *clients; GList *nodes; GList *ports; GList *connections; diff --git a/pinos/client/properties.c b/pinos/client/properties.c index 48d3eeeb3..fc5677f1c 100644 --- a/pinos/client/properties.c +++ b/pinos/client/properties.c @@ -82,6 +82,33 @@ pinos_properties_copy (PinosProperties *properties) return copy; } +PinosProperties * +pinos_properties_merge (PinosProperties *oldprops, + PinosProperties *newprops) +{ + PinosProperties *res = NULL; + + if (oldprops == NULL) { + if (newprops == NULL) + res = NULL; + else + res = pinos_properties_copy (newprops); + } else if (newprops == NULL) { + res = pinos_properties_copy (oldprops); + } else { + const gchar *key; + gpointer state = NULL; + + res = pinos_properties_copy (oldprops); + while ((key = pinos_properties_iterate (newprops, &state))) { + pinos_properties_set (res, + key, + pinos_properties_get (newprops, key)); + } + } + return res; +} + /** * pinos_properties_free: * @properties: a #PinosProperties diff --git a/pinos/client/properties.h b/pinos/client/properties.h index 3b3976477..545c65573 100644 --- a/pinos/client/properties.h +++ b/pinos/client/properties.h @@ -31,6 +31,8 @@ GType pinos_properties_get_type (void); PinosProperties * pinos_properties_new (const gchar *key, ...) G_GNUC_NULL_TERMINATED; PinosProperties * pinos_properties_copy (PinosProperties *properties); +PinosProperties * pinos_properties_merge (PinosProperties *oldprops, + PinosProperties *newprops); void pinos_properties_free (PinosProperties *properties); void pinos_properties_set (PinosProperties *properties, diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 1685e014d..d2c36bbab 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -580,6 +580,7 @@ do_connect (PinosStream *stream) PinosContext *context = priv->context; pinos_context_create_node (context, + "client-node", "client-node", priv->properties, NULL, /* GCancellable *cancellable */ diff --git a/pinos/client/subscribe.c b/pinos/client/subscribe.c index 3b235df10..089d6abb7 100644 --- a/pinos/client/subscribe.c +++ b/pinos/client/subscribe.c @@ -102,9 +102,6 @@ notify_event (PinosSubscribe *subscribe, if (g_strcmp0 (interface_name, "org.pinos.Daemon1") == 0) { flags = PINOS_SUBSCRIPTION_FLAG_DAEMON; } - else if (g_strcmp0 (interface_name, "org.pinos.Client1") == 0) { - flags = PINOS_SUBSCRIPTION_FLAG_CLIENT; - } else if (g_strcmp0 (interface_name, "org.pinos.Node1") == 0) { flags = PINOS_SUBSCRIPTION_FLAG_NODE; } diff --git a/pinos/client/subscribe.h b/pinos/client/subscribe.h index 245c6ab2b..eb14a2b1a 100644 --- a/pinos/client/subscribe.h +++ b/pinos/client/subscribe.h @@ -46,12 +46,11 @@ typedef enum { typedef enum { PINOS_SUBSCRIPTION_FLAG_DAEMON = (1 << 0), - PINOS_SUBSCRIPTION_FLAG_CLIENT = (1 << 1), - PINOS_SUBSCRIPTION_FLAG_NODE = (1 << 2), - PINOS_SUBSCRIPTION_FLAG_PORT = (1 << 3) + PINOS_SUBSCRIPTION_FLAG_NODE = (1 << 1), + PINOS_SUBSCRIPTION_FLAG_PORT = (1 << 2) } PinosSubscriptionFlags; -#define PINOS_SUBSCRIPTION_FLAGS_ALL 0x0f +#define PINOS_SUBSCRIPTION_FLAGS_ALL 0x07 typedef enum { PINOS_SUBSCRIPTION_EVENT_NEW = 0, diff --git a/pinos/dbus/org.pinos.xml b/pinos/dbus/org.pinos.xml index 42c5c4c33..665863ae0 100644 --- a/pinos/dbus/org.pinos.xml +++ b/pinos/dbus/org.pinos.xml @@ -22,63 +22,21 @@ - - - - - - - - - - - - - - - - + + - - - - - - - - - +