* [PATCH 1/6] dbus: Add l_dbus_message_builder_append_from_valist
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
2017-12-04 18:25 ` Denis Kenzior
2017-12-01 15:06 ` [PATCH 2/6] dbus: Use l_dbus_message_builder_append_from_valist in append_arguments Szymon Janc
` (4 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 6541 bytes --]
This allows to build messages from va_list.
---
ell/dbus-message.c | 222 +++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/dbus.h | 4 +
2 files changed, 226 insertions(+)
diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index 0314a07..6e64a13 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1930,6 +1930,228 @@ LIB_EXPORT bool l_dbus_message_builder_append_from_iter(
return true;
}
+LIB_EXPORT bool l_dbus_message_builder_append_from_valist(
+ struct l_dbus_message_builder *builder,
+ const char *signature, va_list args)
+{
+ struct builder_driver *driver;
+ char subsig[256];
+ const char *sigend;
+ /* Nesting requires an extra stack entry for the base level */
+ struct container stack[DBUS_MAX_NESTING + 1];
+ unsigned int stack_index = 0;
+
+ if (unlikely(!builder))
+ return false;
+
+ driver = builder->driver;
+
+ stack[stack_index].type = DBUS_CONTAINER_TYPE_STRUCT;
+ stack[stack_index].sig_start = signature;
+ stack[stack_index].sig_end = signature + strlen(signature);
+ stack[stack_index].n_items = 0;
+
+ while (stack_index != 0 || stack[0].sig_start != stack[0].sig_end) {
+ const char *s;
+ const char *str;
+
+ if (stack[stack_index].type == DBUS_CONTAINER_TYPE_ARRAY &&
+ stack[stack_index].n_items == 0)
+ stack[stack_index].sig_start =
+ stack[stack_index].sig_end;
+
+ if (stack[stack_index].sig_start ==
+ stack[stack_index].sig_end) {
+ bool ret;
+
+ /*
+ * Sanity check in case of an invalid signature that
+ * isn't caught elsewhere.
+ */
+ if (unlikely(stack_index == 0))
+ return false;
+
+ switch (stack[stack_index].type) {
+ case DBUS_CONTAINER_TYPE_STRUCT:
+ ret = driver->leave_struct(builder->builder);
+ break;
+ case DBUS_CONTAINER_TYPE_DICT_ENTRY:
+ ret = driver->leave_dict(builder->builder);
+ break;
+ case DBUS_CONTAINER_TYPE_VARIANT:
+ ret = driver->leave_variant(builder->builder);
+ break;
+ case DBUS_CONTAINER_TYPE_ARRAY:
+ ret = driver->leave_array(builder->builder);
+ break;
+ default:
+ ret = false;
+ }
+
+ if (!ret)
+ return false;
+
+ stack_index -= 1;
+ continue;
+ }
+
+ s = stack[stack_index].sig_start;
+
+ if (stack[stack_index].type != DBUS_CONTAINER_TYPE_ARRAY)
+ stack[stack_index].sig_start += 1;
+ else
+ stack[stack_index].n_items -= 1;
+
+ switch (*s) {
+ case 'o':
+ case 's':
+ case 'g':
+ str = va_arg(args, const char *);
+
+ if (!driver->append_basic(builder->builder, *s, str))
+ return false;
+ break;
+ case 'b':
+ case 'y':
+ {
+ uint8_t y = (uint8_t) va_arg(args, int);
+
+ if (!driver->append_basic(builder->builder, *s, &y))
+ return false;
+
+ break;
+ }
+ case 'n':
+ case 'q':
+ {
+ uint16_t n = (uint16_t) va_arg(args, int);
+
+ if (!driver->append_basic(builder->builder, *s, &n))
+ return false;
+
+ break;
+ }
+ case 'i':
+ case 'u':
+ {
+ uint32_t u = va_arg(args, uint32_t);
+
+ if (!driver->append_basic(builder->builder, *s, &u))
+ return false;
+
+ break;
+ }
+ case 'h':
+ {
+ int fd = va_arg(args, int);
+ struct l_dbus_message *message = builder->message;
+
+ if (!driver->append_basic(builder->builder, *s,
+ &message->num_fds))
+ return false;
+
+ if (message->num_fds < L_ARRAY_SIZE(message->fds))
+ message->fds[message->num_fds++] =
+ fcntl(fd, F_DUPFD_CLOEXEC, 3);
+
+ break;
+ }
+ case 'x':
+ case 't':
+ {
+ uint64_t x = va_arg(args, uint64_t);
+
+ if (!driver->append_basic(builder->builder, *s, &x))
+ return false;
+ break;
+ }
+ case 'd':
+ {
+ double d = va_arg(args, double);
+
+ if (!driver->append_basic(builder->builder, *s, &d))
+ return false;
+ break;
+ }
+ case '(':
+ case '{':
+ if (stack_index == DBUS_MAX_NESTING)
+ return false;
+
+ sigend = _dbus_signature_end(s);
+ memcpy(subsig, s + 1, sigend - s - 1);
+ subsig[sigend - s - 1] = '\0';
+
+ if (*s == '(' && !driver->enter_struct(builder->builder,
+ subsig))
+ return false;
+
+ if (*s == '{' && !driver->enter_dict(builder->builder,
+ subsig))
+ return false;
+
+ if (stack[stack_index].type !=
+ DBUS_CONTAINER_TYPE_ARRAY)
+ stack[stack_index].sig_start = sigend + 1;
+
+ stack_index += 1;
+ stack[stack_index].sig_start = s + 1;
+ stack[stack_index].sig_end = sigend;
+ stack[stack_index].n_items = 0;
+ stack[stack_index].type = *s == '(' ?
+ DBUS_CONTAINER_TYPE_STRUCT :
+ DBUS_CONTAINER_TYPE_DICT_ENTRY;
+
+ break;
+ case 'v':
+ if (stack_index == DBUS_MAX_NESTING)
+ return false;
+
+ str = va_arg(args, const char *);
+
+ if (!str)
+ return false;
+
+ if (!driver->enter_variant(builder->builder, str))
+ return false;
+
+ stack_index += 1;
+ stack[stack_index].type = DBUS_CONTAINER_TYPE_VARIANT;
+ stack[stack_index].sig_start = str;
+ stack[stack_index].sig_end = str + strlen(str);
+ stack[stack_index].n_items = 0;
+
+ break;
+ case 'a':
+ if (stack_index == DBUS_MAX_NESTING)
+ return false;
+
+ sigend = _dbus_signature_end(s + 1) + 1;
+ memcpy(subsig, s + 1, sigend - s - 1);
+ subsig[sigend - s - 1] = '\0';
+
+ if (!driver->enter_array(builder->builder, subsig))
+ return false;
+
+ if (stack[stack_index].type !=
+ DBUS_CONTAINER_TYPE_ARRAY)
+ stack[stack_index].sig_start = sigend;
+
+ stack_index += 1;
+ stack[stack_index].sig_start = s + 1;
+ stack[stack_index].sig_end = sigend;
+ stack[stack_index].n_items = va_arg(args, unsigned int);
+ stack[stack_index].type = DBUS_CONTAINER_TYPE_ARRAY;
+
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
LIB_EXPORT struct l_dbus_message *l_dbus_message_builder_finalize(
struct l_dbus_message_builder *builder)
{
diff --git a/ell/dbus.h b/ell/dbus.h
index 5c7879f..1b1ec2b 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -214,6 +214,10 @@ bool l_dbus_message_builder_append_from_iter(
struct l_dbus_message_builder *builder,
struct l_dbus_message_iter *from);
+bool l_dbus_message_builder_append_from_valist(
+ struct l_dbus_message_builder *builder,
+ const char *signature, va_list args);
+
struct l_dbus_message *l_dbus_message_builder_finalize(
struct l_dbus_message_builder *builder);
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/6] dbus: Use l_dbus_message_builder_append_from_valist in append_arguments
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
2017-12-01 15:06 ` [PATCH 1/6] dbus: Add l_dbus_message_builder_append_from_valist Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
2017-12-04 18:25 ` Denis Kenzior
2017-12-01 15:06 ` [PATCH 3/6] dbus: Add support for proxy interface Szymon Janc
` (3 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 6625 bytes --]
Those functions do similar things and code duplication can be avoided.
---
ell/dbus-message.c | 239 +++--------------------------------------------------
1 file changed, 13 insertions(+), 226 deletions(-)
diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index 6e64a13..f4f6b42 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1089,239 +1089,26 @@ struct container {
static bool append_arguments(struct l_dbus_message *message,
const char *signature, va_list args)
{
- struct dbus_builder *builder;
- struct builder_driver *driver;
- char *generated_signature;
- char subsig[256];
- const char *sigend;
- /* Nesting requires an extra stack entry for the base level */
- struct container stack[DBUS_MAX_NESTING + 1];
- unsigned int stack_index = 0;
-
- if (_dbus_message_is_gvariant(message))
- driver = &gvariant_driver;
- else
- driver = &dbus1_driver;
-
- builder = driver->new(NULL, 0);
-
- stack[stack_index].type = DBUS_CONTAINER_TYPE_STRUCT;
- stack[stack_index].sig_start = signature;
- stack[stack_index].sig_end = signature + strlen(signature);
- stack[stack_index].n_items = 0;
-
- while (stack_index != 0 || stack[0].sig_start != stack[0].sig_end) {
- const char *s;
- const char *str;
-
- if (stack[stack_index].type == DBUS_CONTAINER_TYPE_ARRAY &&
- stack[stack_index].n_items == 0)
- stack[stack_index].sig_start =
- stack[stack_index].sig_end;
-
- if (stack[stack_index].sig_start ==
- stack[stack_index].sig_end) {
- bool ret;
-
- /*
- * Sanity check in case of an invalid signature that
- * isn't caught elsewhere.
- */
- if (unlikely(stack_index == 0))
- goto error;
-
- switch (stack[stack_index].type) {
- case DBUS_CONTAINER_TYPE_STRUCT:
- ret = driver->leave_struct(builder);
- break;
- case DBUS_CONTAINER_TYPE_DICT_ENTRY:
- ret = driver->leave_dict(builder);
- break;
- case DBUS_CONTAINER_TYPE_VARIANT:
- ret = driver->leave_variant(builder);
- break;
- case DBUS_CONTAINER_TYPE_ARRAY:
- ret = driver->leave_array(builder);
- break;
- default:
- ret = false;
- }
-
- if (!ret)
- goto error;
-
- stack_index -= 1;
- continue;
- }
-
- s = stack[stack_index].sig_start;
-
- if (stack[stack_index].type != DBUS_CONTAINER_TYPE_ARRAY)
- stack[stack_index].sig_start += 1;
- else
- stack[stack_index].n_items -= 1;
-
- switch (*s) {
- case 'o':
- case 's':
- case 'g':
- str = va_arg(args, const char *);
-
- if (!driver->append_basic(builder, *s, str))
- goto error;
- break;
- case 'b':
- case 'y':
- {
- uint8_t y = (uint8_t) va_arg(args, int);
-
- if (!driver->append_basic(builder, *s, &y))
- goto error;
-
- break;
- }
- case 'n':
- case 'q':
- {
- uint16_t n = (uint16_t) va_arg(args, int);
-
- if (!driver->append_basic(builder, *s, &n))
- goto error;
-
- break;
- }
- case 'i':
- case 'u':
- {
- uint32_t u = va_arg(args, uint32_t);
-
- if (!driver->append_basic(builder, *s, &u))
- goto error;
-
- break;
- }
- case 'h':
- {
- int fd = va_arg(args, int);
-
- if (!driver->append_basic(builder, *s,
- &message->num_fds))
- goto error;
-
- if (message->num_fds < L_ARRAY_SIZE(message->fds))
- message->fds[message->num_fds++] =
- fcntl(fd, F_DUPFD_CLOEXEC, 3);
-
- break;
- }
- case 'x':
- case 't':
- {
- uint64_t x = va_arg(args, uint64_t);
-
- if (!driver->append_basic(builder, *s, &x))
- goto error;
- break;
- }
- case 'd':
- {
- double d = va_arg(args, double);
-
- if (!driver->append_basic(builder, *s, &d))
- goto error;
- break;
- }
- case '(':
- case '{':
- if (stack_index == DBUS_MAX_NESTING)
- goto error;
-
- sigend = _dbus_signature_end(s);
- memcpy(subsig, s + 1, sigend - s - 1);
- subsig[sigend - s - 1] = '\0';
-
- if (*s == '(' && !driver->enter_struct(builder, subsig))
- goto error;
-
- if (*s == '{' && !driver->enter_dict(builder, subsig))
- goto error;
-
- if (stack[stack_index].type !=
- DBUS_CONTAINER_TYPE_ARRAY)
- stack[stack_index].sig_start = sigend + 1;
-
- stack_index += 1;
- stack[stack_index].sig_start = s + 1;
- stack[stack_index].sig_end = sigend;
- stack[stack_index].n_items = 0;
- stack[stack_index].type = *s == '(' ?
- DBUS_CONTAINER_TYPE_STRUCT :
- DBUS_CONTAINER_TYPE_DICT_ENTRY;
-
- break;
- case 'v':
- if (stack_index == DBUS_MAX_NESTING)
- goto error;
-
- str = va_arg(args, const char *);
-
- if (!str)
- goto error;
-
- if (!driver->enter_variant(builder, str))
- goto error;
-
- stack_index += 1;
- stack[stack_index].type = DBUS_CONTAINER_TYPE_VARIANT;
- stack[stack_index].sig_start = str;
- stack[stack_index].sig_end = str + strlen(str);
- stack[stack_index].n_items = 0;
-
- break;
- case 'a':
- if (stack_index == DBUS_MAX_NESTING)
- goto error;
-
- sigend = _dbus_signature_end(s + 1) + 1;
- memcpy(subsig, s + 1, sigend - s - 1);
- subsig[sigend - s - 1] = '\0';
+ struct l_dbus_message_builder *builder;
+ bool ret;
- if (!driver->enter_array(builder, subsig))
- goto error;
-
- if (stack[stack_index].type !=
- DBUS_CONTAINER_TYPE_ARRAY)
- stack[stack_index].sig_start = sigend;
-
- stack_index += 1;
- stack[stack_index].sig_start = s + 1;
- stack[stack_index].sig_end = sigend;
- stack[stack_index].n_items = va_arg(args, unsigned int);
- stack[stack_index].type = DBUS_CONTAINER_TYPE_ARRAY;
+ builder = l_dbus_message_builder_new(message);
+ if (!builder)
+ return false;
- break;
- default:
- goto error;
- }
+ if (!l_dbus_message_builder_append_from_valist(builder, signature,
+ args)) {
+ l_dbus_message_builder_destroy(builder);
+ return false;
}
- generated_signature = driver->finish(builder, &message->body,
- &message->body_size);
- driver->free(builder);
+ l_dbus_message_builder_finalize(builder);
- if (strcmp(signature, generated_signature))
- return false;
+ ret = strcmp(signature, builder->message->signature) == 0;
- build_header(message, signature);
- message->sealed = true;
- message->signature = generated_signature;
- message->signature_free = true;
+ l_dbus_message_builder_destroy(builder);
- return true;
-
-error:
- driver->free(builder);
- return false;
+ return ret;
}
LIB_EXPORT bool l_dbus_message_get_error(struct l_dbus_message *message,
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 3/6] dbus: Add support for proxy interface
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
2017-12-01 15:06 ` [PATCH 1/6] dbus: Add l_dbus_message_builder_append_from_valist Szymon Janc
2017-12-01 15:06 ` [PATCH 2/6] dbus: Use l_dbus_message_builder_append_from_valist in append_arguments Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
2017-12-04 18:40 ` Denis Kenzior
2017-12-01 15:06 ` [PATCH 4/6] dbus: Add support for setting properties on D-Bus " Szymon Janc
` (2 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 19449 bytes --]
---
Makefile.am | 2 +
ell/dbus-client.c | 570 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/dbus-client.h | 82 ++++++++
ell/ell.h | 1 +
4 files changed, 655 insertions(+)
create mode 100644 ell/dbus-client.c
create mode 100644 ell/dbus-client.h
diff --git a/Makefile.am b/Makefile.am
index a95bac4..19b957e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@ pkginclude_HEADERS = ell/ell.h \
ell/genl.h \
ell/dbus.h \
ell/dbus-service.h \
+ ell/dbus-client.h \
ell/hwdb.h \
ell/cipher.h \
ell/random.h \
@@ -74,6 +75,7 @@ ell_libell_la_SOURCES = $(linux_headers) \
ell/dbus-message.c \
ell/dbus-util.c \
ell/dbus-service.c \
+ ell/dbus-client.c \
ell/dbus-name-cache.c \
ell/dbus-filter.c \
ell/gvariant-private.h \
diff --git a/ell/dbus-client.c b/ell/dbus-client.c
new file mode 100644
index 0000000..f07a183
--- /dev/null
+++ b/ell/dbus-client.c
@@ -0,0 +1,570 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2017 Codecoup. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ell.h"
+#include "private.h"
+
+struct l_dbus_client {
+ struct l_dbus *dbus;
+ unsigned int watch;
+ unsigned int added_watch;
+ unsigned int removed_watch;
+ char *service;
+ char *path;
+ uint32_t objects_call;
+
+ l_dbus_watch_func_t connect_cb;
+ void *connect_cb_data;
+ l_dbus_destroy_func_t connect_cb_data_destroy;
+
+ l_dbus_watch_func_t disconnect_cb;
+ void *disconnect_cb_data;
+ l_dbus_destroy_func_t disconnect_cb_data_destroy;
+
+ l_dbus_client_ready_func_t ready_cb;
+ void *ready_cb_data;
+ l_dbus_destroy_func_t ready_cb_data_destroy;
+
+ l_dbus_client_proxy_func_t proxy_added_cb;
+ l_dbus_client_proxy_func_t proxy_removed_cb;
+ l_dbus_client_property_function_t properties_changed_cb;
+ void *proxy_cb_data;
+ l_dbus_destroy_func_t proxy_cb_data_destroy;
+
+ struct l_queue *proxies;
+};
+
+struct proxy_property {
+ char *name;
+ struct l_dbus_message *msg;
+};
+
+struct l_dbus_proxy {
+ struct l_dbus_client *client;
+ char *interface;
+ char *path;
+ uint32_t properties_watch;
+ bool ready;
+
+ struct l_queue *properties;
+};
+
+LIB_EXPORT const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy)
+{
+ if (unlikely(!proxy))
+ return NULL;
+
+ return proxy->path;
+}
+
+LIB_EXPORT const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy)
+{
+ if (unlikely(!proxy))
+ return NULL;
+
+ return proxy->interface;
+}
+
+static bool property_match_by_name(const void *a, const void *b)
+{
+ const struct proxy_property *prop = a;
+ const char *name = b;
+
+ return !strcmp(prop->name, name);
+}
+
+static struct proxy_property *find_property(struct l_dbus_proxy *proxy,
+ const char *name)
+{
+ return l_queue_find(proxy->properties, property_match_by_name, name);
+}
+
+static struct proxy_property *get_property(struct l_dbus_proxy *proxy,
+ const char *name)
+{
+ struct proxy_property *prop;
+
+ prop = find_property(proxy, name);
+ if (prop)
+ return prop;
+
+ prop = l_new(struct proxy_property, 1);
+ prop->name = l_strdup(name);
+
+ l_queue_push_tail(proxy->properties, prop);
+
+ return prop;
+}
+
+LIB_EXPORT bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy,
+ const char *name,
+ const char *signature, ...)
+{
+ struct proxy_property *prop;
+ va_list args;
+ bool res;
+
+ if (unlikely(!proxy))
+ return false;
+
+ prop = find_property(proxy, name);
+ if (!prop)
+ return false;
+
+ va_start(args, signature);
+ res = l_dbus_message_get_arguments_valist(prop->msg, signature, args);
+ va_end(args);
+
+ return res;
+}
+
+static void property_free(void *data)
+{
+ struct proxy_property *prop = data;
+
+ if (prop->msg)
+ l_dbus_message_unref(prop->msg);
+
+ l_free(prop->name);
+ l_free(prop);
+}
+
+static void l_dbus_proxy_destroy(struct l_dbus_proxy *proxy)
+{
+ if (unlikely(!proxy))
+ return;
+
+ if (proxy->properties_watch)
+ l_dbus_remove_signal_watch(proxy->client->dbus,
+ proxy->properties_watch);
+
+ l_queue_destroy(proxy->properties, property_free);
+ l_free(proxy->interface);
+ l_free(proxy->path);
+ l_free(proxy);
+}
+
+static void proxy_update_property(struct l_dbus_proxy *proxy,
+ const char *name,
+ struct l_dbus_message_iter *property)
+{
+ struct l_dbus_message_builder *builder;
+ struct proxy_property *prop = get_property(proxy, name);
+
+ l_dbus_message_unref(prop->msg);
+
+ if (!property) {
+ prop->msg = NULL;
+ goto done;
+ }
+
+ prop->msg = l_dbus_message_new_signal(proxy->client->dbus, proxy->path,
+ proxy->interface, name);
+ if (!prop->msg)
+ return;
+
+ builder = l_dbus_message_builder_new(prop->msg);
+ l_dbus_message_builder_append_from_iter(builder, property);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+done:
+ if (proxy->client->properties_changed_cb && proxy->ready)
+ proxy->client->properties_changed_cb(proxy, name, prop->msg,
+ proxy->client->proxy_cb_data_destroy);
+}
+
+static void proxy_invalidate_properties(struct l_dbus_proxy *proxy,
+ struct l_dbus_message_iter* props)
+{
+ const char *name;
+
+ while (l_dbus_message_iter_next_entry(props, &name))
+ proxy_update_property(proxy, name, NULL);
+}
+
+static void proxy_update_properties(struct l_dbus_proxy *proxy,
+ struct l_dbus_message_iter* props)
+{
+ struct l_dbus_message_iter variant;
+ const char *name;
+
+ while (l_dbus_message_iter_next_entry(props, &name, &variant))
+ proxy_update_property(proxy, name, &variant);
+}
+
+static void properties_changed_callback(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_proxy *proxy = user_data;
+ const char *interface;
+ struct l_dbus_message_iter changed;
+ struct l_dbus_message_iter invalidated;
+
+ if (!l_dbus_message_get_arguments(message, "sa{sv}as", &interface,
+ &changed, &invalidated))
+ return;
+
+ proxy_update_properties(proxy, &changed);
+ proxy_invalidate_properties(proxy, &invalidated);
+}
+
+static struct l_dbus_proxy *l_dbus_proxy_new(struct l_dbus_client *client,
+ const char *path, const char *interface)
+{
+ struct l_dbus_proxy *proxy;
+
+ proxy = l_new(struct l_dbus_proxy, 1);
+
+ proxy->properties_watch = l_dbus_add_signal_watch(client->dbus,
+ client->service, path,
+ L_DBUS_INTERFACE_PROPERTIES,
+ "PropertiesChanged",
+ L_DBUS_MATCH_ARGUMENT(0),
+ interface, L_DBUS_MATCH_NONE,
+ properties_changed_callback,
+ proxy);
+ if (!proxy->properties_watch) {
+ l_free(proxy);
+ return NULL;
+ }
+
+ proxy->client = client;
+ proxy->interface = l_strdup(interface);
+ proxy->path = l_strdup(path);
+ proxy->properties = l_queue_new();
+
+ l_queue_push_tail(client->proxies, proxy);
+
+ return proxy;
+}
+
+static bool is_ignorable(const char *interface)
+{
+ static const struct {
+ const char *interface;
+ } interfaces_to_ignore[] = {
+ { L_DBUS_INTERFACE_OBJECT_MANAGER },
+ { L_DBUS_INTERFACE_INTROSPECTABLE },
+ { L_DBUS_INTERFACE_PROPERTIES },
+ };
+ size_t i;
+
+ for (i = 0; i < L_ARRAY_SIZE(interfaces_to_ignore); i++)
+ if (!strcmp(interfaces_to_ignore[i].interface, interface))
+ return true;
+
+ return false;
+}
+
+static struct l_dbus_proxy *find_proxy(struct l_dbus_client *client,
+ const char *path, const char *interface)
+{
+ const struct l_queue_entry *entry;
+
+ for (entry = l_queue_get_entries(client->proxies); entry;
+ entry = entry->next) {
+ struct l_dbus_proxy *proxy = entry->data;
+
+ if (!strcmp(proxy->interface, interface) &&
+ !strcmp(proxy->path, path))
+ return proxy;
+ }
+
+ return NULL;
+}
+
+static void parse_interface(struct l_dbus_client *client, const char *path,
+ const char *interface,
+ struct l_dbus_message_iter *properties)
+{
+ struct l_dbus_proxy *proxy;
+
+ if (is_ignorable(interface))
+ return;
+
+ proxy = find_proxy(client, path, interface);
+ if (!proxy) {
+ proxy = l_dbus_proxy_new(client, path, interface);
+ }
+
+ if (!proxy)
+ return;
+
+ proxy_update_properties(proxy, properties);
+
+ if (!proxy->ready) {
+ proxy->ready = true;
+
+ if (client->proxy_added_cb)
+ client->proxy_added_cb(proxy, client->proxy_cb_data);
+ }
+}
+
+static void parse_object(struct l_dbus_client *client, const char *path,
+ struct l_dbus_message_iter *object)
+{
+ const char *interface;
+ struct l_dbus_message_iter properties;
+
+ if (!path)
+ return;
+
+ while (l_dbus_message_iter_next_entry(object, &interface, &properties))
+ parse_interface(client, path, interface, &properties);
+}
+
+static void interfaces_added_callback(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_client *client = user_data;
+ struct l_dbus_message_iter object;
+ const char *path;
+
+ if (!l_dbus_message_get_arguments(message, "oa{sa{sv}}", &path,
+ &object))
+ return
+
+ parse_object(client, path, &object);
+}
+
+static void interfaces_removed_callback(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_client *client = user_data;
+ struct l_dbus_message_iter interfaces;
+ const char *interface;
+ const char *path;
+
+ if (!l_dbus_message_get_arguments(message, "oas", &path, &interfaces))
+ return;
+
+ while (l_dbus_message_iter_next_entry(&interfaces, &interface)) {
+ struct l_dbus_proxy *proxy;
+
+ proxy = find_proxy(client, path, interface);
+ if (!proxy)
+ continue;
+
+ l_queue_remove(proxy->client->proxies, proxy);
+
+ if (client->proxy_removed_cb)
+ client->proxy_removed_cb(proxy, client->proxy_cb_data);
+
+ l_dbus_proxy_destroy(proxy);
+ }
+}
+
+static void get_managed_objects_reply(struct l_dbus_message *message,
+ void *user_data)
+{
+ struct l_dbus_client *client = user_data;
+ struct l_dbus_message_iter objects;
+ struct l_dbus_message_iter object;
+ const char *path;
+
+ client->objects_call = 0;
+
+ if (l_dbus_message_is_error(message))
+ return;
+
+ l_dbus_message_get_arguments(message, "a{oa{sa{sv}}}", &objects);
+
+ while (l_dbus_message_iter_next_entry(&objects, &path, &object))
+ parse_object(client, path, &object);
+
+ client->added_watch = l_dbus_add_signal_watch(client->dbus,
+ client->service, "/",
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesAdded",
+ L_DBUS_MATCH_NONE,
+ interfaces_added_callback,
+ client);
+
+ client->removed_watch = l_dbus_add_signal_watch(client->dbus,
+ client->service, "/",
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "InterfacesRemoved",
+ L_DBUS_MATCH_NONE,
+ interfaces_removed_callback,
+ client);
+
+ if (client->ready_cb)
+ client->ready_cb(client, client->ready_cb_data);
+}
+
+static void service_appeared_callback(struct l_dbus *dbus, void *user_data)
+{
+ struct l_dbus_client *client = user_data;
+
+ /* TODO should we allow to set different root? */
+ client->objects_call = l_dbus_method_call(dbus, client->service, "/",
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_reply,
+ client, NULL);
+
+ if (client->connect_cb)
+ client->connect_cb(client->dbus, client->connect_cb_data);
+}
+
+static void service_disappeared_callback(struct l_dbus *dbus, void *user_data)
+{
+ struct l_dbus_client *client = user_data;
+
+ if (client->disconnect_cb)
+ client->disconnect_cb(client->dbus, client->disconnect_cb_data);
+
+ l_queue_clear(client->proxies,
+ (l_queue_destroy_func_t)l_dbus_proxy_destroy);
+}
+
+LIB_EXPORT struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus,
+ const char *service, const char *path)
+{
+ struct l_dbus_client *client;
+
+ client = l_new(struct l_dbus_client, 1);
+
+ client->dbus = dbus;
+
+ client->watch = l_dbus_add_service_watch(dbus, service,
+ service_appeared_callback,
+ service_disappeared_callback,
+ client, NULL);
+
+ if (!client->watch) {
+ l_free(client);
+ return NULL;
+ }
+
+ client->service = l_strdup(service);
+ client->path = l_strdup(path);
+ client->proxies = l_queue_new();
+
+ return client;
+}
+
+LIB_EXPORT void l_dbus_client_destroy(struct l_dbus_client *client)
+{
+ if (unlikely(!client))
+ return;
+
+ if (client->watch)
+ l_dbus_remove_signal_watch(client->dbus, client->watch);
+
+ if (client->added_watch)
+ l_dbus_remove_signal_watch(client->dbus, client->added_watch);
+
+ if (client->removed_watch)
+ l_dbus_remove_signal_watch(client->dbus, client->removed_watch);
+
+ if (client->connect_cb_data_destroy)
+ client->connect_cb_data_destroy(client->connect_cb_data);
+
+ if (client->disconnect_cb_data_destroy)
+ client->disconnect_cb_data_destroy(client->disconnect_cb_data);
+
+ if (client->ready_cb_data_destroy)
+ client->ready_cb_data_destroy(client->ready_cb_data);
+
+ if (client->proxy_cb_data_destroy)
+ client->proxy_cb_data_destroy(client->proxy_cb_data);
+
+ if (client->objects_call)
+ l_dbus_cancel(client->dbus, client->objects_call)
+;
+ l_queue_destroy(client->proxies,
+ (l_queue_destroy_func_t)l_dbus_proxy_destroy);
+
+ l_free(client->service);
+ l_free(client->path);
+ l_free(client);
+}
+
+LIB_EXPORT bool l_dbus_client_set_connect_handler(struct l_dbus_client *client,
+ l_dbus_watch_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy)
+{
+ if (unlikely(!client))
+ return false;
+
+ client->connect_cb = function;
+ client->connect_cb_data = user_data;
+ client->connect_cb_data_destroy = destroy;
+
+ return true;
+}
+
+LIB_EXPORT bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client,
+ l_dbus_watch_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy)
+{
+ if (unlikely(!client))
+ return false;
+
+ client->disconnect_cb = function;
+ client->disconnect_cb_data = user_data;
+ client->disconnect_cb_data_destroy = destroy;
+
+ return true;
+}
+
+LIB_EXPORT bool l_dbus_client_set_ready_handler(struct l_dbus_client *client,
+ l_dbus_client_ready_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy)
+{
+ if (unlikely(!client))
+ return false;
+
+ client->ready_cb = function;
+ client->ready_cb_data = user_data;
+ client->ready_cb_data_destroy = destroy;
+
+ return true;
+}
+
+LIB_EXPORT bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client,
+ l_dbus_client_proxy_func_t proxy_added,
+ l_dbus_client_proxy_func_t proxy_removed,
+ l_dbus_client_property_function_t property_changed,
+ void *user_data, l_dbus_destroy_func_t destroy)
+{
+ if (unlikely(!client))
+ return false;
+
+ client->proxy_added_cb = proxy_added;
+ client->proxy_removed_cb = proxy_removed;
+ client->properties_changed_cb = property_changed;
+ client->proxy_cb_data = user_data;
+ client->proxy_cb_data_destroy = destroy;
+
+ return true;
+}
diff --git a/ell/dbus-client.h b/ell/dbus-client.h
new file mode 100644
index 0000000..460c6c5
--- /dev/null
+++ b/ell/dbus-client.h
@@ -0,0 +1,82 @@
+/*
+ *
+ * Embedded Linux library
+ *
+ * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2017 Codecoup. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 __ELL_DBUS_CLIENT_H
+#define __ELL_DBUS_CLIENT_H
+
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct l_dbus;
+struct l_dbus_message;
+struct l_dbus_client;
+struct l_dbus_proxy;
+
+typedef void (*l_dbus_client_ready_func_t)(struct l_dbus_client *client,
+ void *user_data);
+typedef void (*l_dbus_client_proxy_func_t) (struct l_dbus_proxy *proxy,
+ void *user_data);
+typedef void (*l_dbus_client_property_function_t) (struct l_dbus_proxy *proxy,
+ const char *name,
+ struct l_dbus_message *msg,
+ void *user_data);
+
+struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus,
+ const char *service, const char *path);
+void l_dbus_client_destroy(struct l_dbus_client *client);
+
+bool l_dbus_client_set_connect_handler(struct l_dbus_client *client,
+ l_dbus_watch_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy);
+
+bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client,
+ l_dbus_watch_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy);
+
+bool l_dbus_client_set_ready_handler(struct l_dbus_client *client,
+ l_dbus_client_ready_func_t function,
+ void *user_data,
+ l_dbus_destroy_func_t destroy);
+
+bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client,
+ l_dbus_client_proxy_func_t proxy_added,
+ l_dbus_client_proxy_func_t proxy_removed,
+ l_dbus_client_property_function_t property_changed,
+ void *user_data, l_dbus_destroy_func_t destroy);
+
+const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy);
+
+const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy);
+
+bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, const char *name,
+ const char *signature, ...);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __ELL_DBUS_CLIENT_H */
diff --git a/ell/ell.h b/ell/ell.h
index 2efd1c4..4083ee5 100644
--- a/ell/ell.h
+++ b/ell/ell.h
@@ -51,3 +51,4 @@
#include <ell/genl.h>
#include <ell/dbus.h>
#include <ell/dbus-service.h>
+#include <ell/dbus-client.h>
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 3/6] dbus: Add support for proxy interface
2017-12-01 15:06 ` [PATCH 3/6] dbus: Add support for proxy interface Szymon Janc
@ 2017-12-04 18:40 ` Denis Kenzior
2017-12-05 17:05 ` Szymon Janc
0 siblings, 1 reply; 11+ messages in thread
From: Denis Kenzior @ 2017-12-04 18:40 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 7616 bytes --]
Hi Szymon,
<snip>
> +static struct l_dbus_proxy *l_dbus_proxy_new(struct l_dbus_client *client,
> + const char *path, const char *interface)
I would just call it dbus_proxy_new since it is not exported. Same with
l_dbus_proxy_destroy
> +{
> + struct l_dbus_proxy *proxy;
> +
> + proxy = l_new(struct l_dbus_proxy, 1);
can condense these to a single line...
> +
> + proxy->properties_watch = l_dbus_add_signal_watch(client->dbus,
> + client->service, path,
> + L_DBUS_INTERFACE_PROPERTIES,
> + "PropertiesChanged",
> + L_DBUS_MATCH_ARGUMENT(0),
> + interface, L_DBUS_MATCH_NONE,
> + properties_changed_callback,
> + proxy);
> + if (!proxy->properties_watch) {
> + l_free(proxy);
> + return NULL;
> + }
> +
> + proxy->client = client;
> + proxy->interface = l_strdup(interface);
> + proxy->path = l_strdup(path);
> + proxy->properties = l_queue_new();
> +
> + l_queue_push_tail(client->proxies, proxy);
> +
> + return proxy;
> +}
> +
> +static bool is_ignorable(const char *interface)
> +{
> + static const struct {
> + const char *interface;
> + } interfaces_to_ignore[] = {
> + { L_DBUS_INTERFACE_OBJECT_MANAGER },
> + { L_DBUS_INTERFACE_INTROSPECTABLE },
> + { L_DBUS_INTERFACE_PROPERTIES },
> + };
> + size_t i;
> +
> + for (i = 0; i < L_ARRAY_SIZE(interfaces_to_ignore); i++)
> + if (!strcmp(interfaces_to_ignore[i].interface, interface))
> + return true;
> +
> + return false;
> +}
> +
> +static struct l_dbus_proxy *find_proxy(struct l_dbus_client *client,
> + const char *path, const char *interface)
> +{
> + const struct l_queue_entry *entry;
> +
> + for (entry = l_queue_get_entries(client->proxies); entry;
> + entry = entry->next) {
> + struct l_dbus_proxy *proxy = entry->data;
> +
> + if (!strcmp(proxy->interface, interface) &&
> + !strcmp(proxy->path, path))
> + return proxy;
> + }
> +
> + return NULL;
> +}
> +
> +static void parse_interface(struct l_dbus_client *client, const char *path,
> + const char *interface,
> + struct l_dbus_message_iter *properties)
> +{
> + struct l_dbus_proxy *proxy;
> +
> + if (is_ignorable(interface))
> + return;
> +
> + proxy = find_proxy(client, path, interface);
> + if (!proxy) {
> + proxy = l_dbus_proxy_new(client, path, interface);
> + }
No need for {}
> +
> + if (!proxy)
> + return;
> +
> + proxy_update_properties(proxy, properties);
> +
> + if (!proxy->ready) {
> + proxy->ready = true;
> +
> + if (client->proxy_added_cb)
> + client->proxy_added_cb(proxy, client->proxy_cb_data);
> + }
> +}
> +
<snip>
> +
> +static void service_appeared_callback(struct l_dbus *dbus, void *user_data)
> +{
> + struct l_dbus_client *client = user_data;
> +
> + /* TODO should we allow to set different root? */
> + client->objects_call = l_dbus_method_call(dbus, client->service, "/",
> + L_DBUS_INTERFACE_OBJECT_MANAGER,
> + "GetManagedObjects", NULL,
> + get_managed_objects_reply,
> + client, NULL);
> +
> + if (client->connect_cb)
> + client->connect_cb(client->dbus, client->connect_cb_data);
> +}
> +
> +static void service_disappeared_callback(struct l_dbus *dbus, void *user_data)
> +{
> + struct l_dbus_client *client = user_data;
> +
> + if (client->disconnect_cb)
> + client->disconnect_cb(client->dbus, client->disconnect_cb_data);
> +
> + l_queue_clear(client->proxies,
> + (l_queue_destroy_func_t)l_dbus_proxy_destroy);
> +}
> +
> +LIB_EXPORT struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus,
> + const char *service, const char *path)
> +{
> + struct l_dbus_client *client;
> +
> + client = l_new(struct l_dbus_client, 1);
> +
Can condense these to a single line
> + client->dbus = dbus;
> +
> + client->watch = l_dbus_add_service_watch(dbus, service,
> + service_appeared_callback,
> + service_disappeared_callback,
> + client, NULL);
> +
> + if (!client->watch) {
> + l_free(client);
> + return NULL;
> + }
> +
> + client->service = l_strdup(service);
> + client->path = l_strdup(path);
What is the purpose of this member actually? We're not using it for the
ObjectManager root, nor are we using it for anything else. I also don't
get its purpose in gdbus either. Can we simply drop it?
> + client->proxies = l_queue_new();
> +
> + return client;
> +}
> +
> +LIB_EXPORT void l_dbus_client_destroy(struct l_dbus_client *client)
> +{
> + if (unlikely(!client))
> + return;
> +
> + if (client->watch)
> + l_dbus_remove_signal_watch(client->dbus, client->watch);
> +
> + if (client->added_watch)
> + l_dbus_remove_signal_watch(client->dbus, client->added_watch);
> +
> + if (client->removed_watch)
> + l_dbus_remove_signal_watch(client->dbus, client->removed_watch);
> +
> + if (client->connect_cb_data_destroy)
> + client->connect_cb_data_destroy(client->connect_cb_data);
> +
> + if (client->disconnect_cb_data_destroy)
> + client->disconnect_cb_data_destroy(client->disconnect_cb_data);
> +
> + if (client->ready_cb_data_destroy)
> + client->ready_cb_data_destroy(client->ready_cb_data);
> +
> + if (client->proxy_cb_data_destroy)
> + client->proxy_cb_data_destroy(client->proxy_cb_data);
> +
> + if (client->objects_call)
> + l_dbus_cancel(client->dbus, client->objects_call)
> +;
> + l_queue_destroy(client->proxies,
> + (l_queue_destroy_func_t)l_dbus_proxy_destroy);
> +
> + l_free(client->service);
> + l_free(client->path);
> + l_free(client);
> +}
> +
> +LIB_EXPORT bool l_dbus_client_set_connect_handler(struct l_dbus_client *client,
> + l_dbus_watch_func_t function,
> + void *user_data,
> + l_dbus_destroy_func_t destroy)
> +{
> + if (unlikely(!client))
> + return false;
> +
> + client->connect_cb = function;
> + client->connect_cb_data = user_data;
> + client->connect_cb_data_destroy = destroy;
No biggie, but maybe we should call destroy function here in case it is
already set.
> +
> + return true;
> +}
> +
> +LIB_EXPORT bool l_dbus_client_set_disconnect_handler(struct l_dbus_client *client,
> + l_dbus_watch_func_t function,
> + void *user_data,
> + l_dbus_destroy_func_t destroy)
> +{
> + if (unlikely(!client))
> + return false;
> +
> + client->disconnect_cb = function;
> + client->disconnect_cb_data = user_data;
> + client->disconnect_cb_data_destroy = destroy;
as above
> +
> + return true;
> +}
> +
> +LIB_EXPORT bool l_dbus_client_set_ready_handler(struct l_dbus_client *client,
> + l_dbus_client_ready_func_t function,
> + void *user_data,
> + l_dbus_destroy_func_t destroy)
> +{
> + if (unlikely(!client))
> + return false;
> +
> + client->ready_cb = function;
> + client->ready_cb_data = user_data;
> + client->ready_cb_data_destroy = destroy;
as above
> +
> + return true;
> +}
> +
> +LIB_EXPORT bool l_dbus_client_set_proxy_handlers(struct l_dbus_client *client,
> + l_dbus_client_proxy_func_t proxy_added,
> + l_dbus_client_proxy_func_t proxy_removed,
> + l_dbus_client_property_function_t property_changed,
> + void *user_data, l_dbus_destroy_func_t destroy)
> +{
> + if (unlikely(!client))
> + return false;
> +
> + client->proxy_added_cb = proxy_added;
> + client->proxy_removed_cb = proxy_removed;
> + client->properties_changed_cb = property_changed;
> + client->proxy_cb_data = user_data;
> + client->proxy_cb_data_destroy = destroy;
as above
> +
> + return true;
> +}
<snip>
Regards,
-Denis
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 3/6] dbus: Add support for proxy interface
2017-12-04 18:40 ` Denis Kenzior
@ 2017-12-05 17:05 ` Szymon Janc
0 siblings, 0 replies; 11+ messages in thread
From: Szymon Janc @ 2017-12-05 17:05 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 8479 bytes --]
Hi Denis,
On Monday, 4 December 2017 19:40:29 CET Denis Kenzior wrote:
> Hi Szymon,
>
> <snip>
>
> > +static struct l_dbus_proxy *l_dbus_proxy_new(struct l_dbus_client
> > *client,
> > + const char *path, const char *interface)
>
> I would just call it dbus_proxy_new since it is not exported. Same with
> l_dbus_proxy_destroy
Done.
>
> > +{
> > + struct l_dbus_proxy *proxy;
> > +
> > + proxy = l_new(struct l_dbus_proxy, 1);
>
> can condense these to a single line...
OK.
>
> > +
> > + proxy->properties_watch = l_dbus_add_signal_watch(client->dbus,
> > + client->service, path,
> > + L_DBUS_INTERFACE_PROPERTIES,
> > + "PropertiesChanged",
> > + L_DBUS_MATCH_ARGUMENT(0),
> > + interface, L_DBUS_MATCH_NONE,
> > + properties_changed_callback,
> > + proxy);
> > + if (!proxy->properties_watch) {
> > + l_free(proxy);
> > + return NULL;
> > + }
> > +
> > + proxy->client = client;
> > + proxy->interface = l_strdup(interface);
> > + proxy->path = l_strdup(path);
> > + proxy->properties = l_queue_new();
> > +
> > + l_queue_push_tail(client->proxies, proxy);
> > +
> > + return proxy;
> > +}
> > +
> > +static bool is_ignorable(const char *interface)
> > +{
> > + static const struct {
> > + const char *interface;
> > + } interfaces_to_ignore[] = {
> > + { L_DBUS_INTERFACE_OBJECT_MANAGER },
> > + { L_DBUS_INTERFACE_INTROSPECTABLE },
> > + { L_DBUS_INTERFACE_PROPERTIES },
> > + };
> > + size_t i;
> > +
> > + for (i = 0; i < L_ARRAY_SIZE(interfaces_to_ignore); i++)
> > + if (!strcmp(interfaces_to_ignore[i].interface, interface))
> > + return true;
> > +
> > + return false;
> > +}
> > +
> > +static struct l_dbus_proxy *find_proxy(struct l_dbus_client *client,
> > + const char *path, const char *interface)
> > +{
> > + const struct l_queue_entry *entry;
> > +
> > + for (entry = l_queue_get_entries(client->proxies); entry;
> > + entry = entry->next) {
> > + struct l_dbus_proxy *proxy = entry->data;
> > +
> > + if (!strcmp(proxy->interface, interface) &&
> > + !strcmp(proxy->path, path))
> > + return proxy;
> > + }
> > +
> > + return NULL;
> > +}
> > +
> > +static void parse_interface(struct l_dbus_client *client, const char
> > *path, + const char *interface,
> > + struct l_dbus_message_iter *properties)
> > +{
> > + struct l_dbus_proxy *proxy;
> > +
> > + if (is_ignorable(interface))
> > + return;
> > +
> > + proxy = find_proxy(client, path, interface);
> > + if (!proxy) {
> > + proxy = l_dbus_proxy_new(client, path, interface);
> > + }
>
> No need for {}
Fixed.
>
> > +
> > + if (!proxy)
> > + return;
> > +
> > + proxy_update_properties(proxy, properties);
> > +
> > + if (!proxy->ready) {
> > + proxy->ready = true;
> > +
> > + if (client->proxy_added_cb)
> > + client->proxy_added_cb(proxy, client->proxy_cb_data);
> > + }
> > +}
> > +
>
> <snip>
>
> > +
> > +static void service_appeared_callback(struct l_dbus *dbus, void
> > *user_data) +{
> > + struct l_dbus_client *client = user_data;
> > +
> > + /* TODO should we allow to set different root? */
> > + client->objects_call = l_dbus_method_call(dbus, client->service, "/",
> > + L_DBUS_INTERFACE_OBJECT_MANAGER,
> > + "GetManagedObjects", NULL,
> > + get_managed_objects_reply,
> > + client, NULL);
> > +
> > + if (client->connect_cb)
> > + client->connect_cb(client->dbus, client->connect_cb_data);
> > +}
> > +
> > +static void service_disappeared_callback(struct l_dbus *dbus, void
> > *user_data) +{
> > + struct l_dbus_client *client = user_data;
> > +
> > + if (client->disconnect_cb)
> > + client->disconnect_cb(client->dbus, client->disconnect_cb_data);
> > +
> > + l_queue_clear(client->proxies,
> > + (l_queue_destroy_func_t)l_dbus_proxy_destroy);
> > +}
> > +
> > +LIB_EXPORT struct l_dbus_client *l_dbus_client_new(struct l_dbus *dbus,
> > + const char *service, const char *path)
> > +{
> > + struct l_dbus_client *client;
> > +
> > + client = l_new(struct l_dbus_client, 1);
> > +
>
> Can condense these to a single line
OK.
>
> > + client->dbus = dbus;
> > +
> > + client->watch = l_dbus_add_service_watch(dbus, service,
> > + service_appeared_callback,
> > + service_disappeared_callback,
> > + client, NULL);
> > +
> > + if (!client->watch) {
> > + l_free(client);
> > + return NULL;
> > + }
> > +
> > + client->service = l_strdup(service);
> > + client->path = l_strdup(path);
>
> What is the purpose of this member actually? We're not using it for the
> ObjectManager root, nor are we using it for anything else. I also don't
> get its purpose in gdbus either. Can we simply drop it?
Yeap, I think I initially had getter for it that turned out to be useless but
forgot to remove member from client. Fixed.
>
> > + client->proxies = l_queue_new();
> > +
> > + return client;
> > +}
> > +
> > +LIB_EXPORT void l_dbus_client_destroy(struct l_dbus_client *client)
> > +{
> > + if (unlikely(!client))
> > + return;
> > +
> > + if (client->watch)
> > + l_dbus_remove_signal_watch(client->dbus, client->watch);
> > +
> > + if (client->added_watch)
> > + l_dbus_remove_signal_watch(client->dbus, client->added_watch);
> > +
> > + if (client->removed_watch)
> > + l_dbus_remove_signal_watch(client->dbus, client->removed_watch);
> > +
> > + if (client->connect_cb_data_destroy)
> > + client->connect_cb_data_destroy(client->connect_cb_data);
> > +
> > + if (client->disconnect_cb_data_destroy)
> > + client->disconnect_cb_data_destroy(client->disconnect_cb_data);
> > +
> > + if (client->ready_cb_data_destroy)
> > + client->ready_cb_data_destroy(client->ready_cb_data);
> > +
> > + if (client->proxy_cb_data_destroy)
> > + client->proxy_cb_data_destroy(client->proxy_cb_data);
> > +
> > + if (client->objects_call)
> > + l_dbus_cancel(client->dbus, client->objects_call)
> > +;
> > + l_queue_destroy(client->proxies,
> > + (l_queue_destroy_func_t)l_dbus_proxy_destroy);
> > +
> > + l_free(client->service);
> > + l_free(client->path);
> > + l_free(client);
> > +}
> > +
> > +LIB_EXPORT bool l_dbus_client_set_connect_handler(struct l_dbus_client
> > *client, + l_dbus_watch_func_t function,
> > + void *user_data,
> > + l_dbus_destroy_func_t destroy)
> > +{
> > + if (unlikely(!client))
> > + return false;
> > +
> > + client->connect_cb = function;
> > + client->connect_cb_data = user_data;
> > + client->connect_cb_data_destroy = destroy;
>
> No biggie, but maybe we should call destroy function here in case it is
> already set.
OK.
>
> > +
> > + return true;
> > +}
> > +
> > +LIB_EXPORT bool l_dbus_client_set_disconnect_handler(struct l_dbus_client
> > *client, + l_dbus_watch_func_t function,
> > + void *user_data,
> > + l_dbus_destroy_func_t destroy)
> > +{
> > + if (unlikely(!client))
> > + return false;
> > +
> > + client->disconnect_cb = function;
> > + client->disconnect_cb_data = user_data;
> > + client->disconnect_cb_data_destroy = destroy;
>
> as above
>
> > +
> > + return true;
> > +}
> > +
> > +LIB_EXPORT bool l_dbus_client_set_ready_handler(struct l_dbus_client
> > *client, + l_dbus_client_ready_func_t function,
> > + void *user_data,
> > + l_dbus_destroy_func_t destroy)
> > +{
> > + if (unlikely(!client))
> > + return false;
> > +
> > + client->ready_cb = function;
> > + client->ready_cb_data = user_data;
> > + client->ready_cb_data_destroy = destroy;
>
> as above
>
> > +
> > + return true;
> > +}
> > +
> > +LIB_EXPORT bool l_dbus_client_set_proxy_handlers(struct l_dbus_client
> > *client, + l_dbus_client_proxy_func_t proxy_added,
> > + l_dbus_client_proxy_func_t proxy_removed,
> > + l_dbus_client_property_function_t property_changed,
> > + void *user_data, l_dbus_destroy_func_t destroy)
> > +{
> > + if (unlikely(!client))
> > + return false;
> > +
> > + client->proxy_added_cb = proxy_added;
> > + client->proxy_removed_cb = proxy_removed;
> > + client->properties_changed_cb = property_changed;
> > + client->proxy_cb_data = user_data;
> > + client->proxy_cb_data_destroy = destroy;
>
> as above
>
> > +
> > + return true;
> > +}
>
> <snip>
>
> Regards,
> -Denis
--
pozdrawiam
Szymon Janc
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/6] dbus: Add support for setting properties on D-Bus proxy interface
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
` (2 preceding siblings ...)
2017-12-01 15:06 ` [PATCH 3/6] dbus: Add support for proxy interface Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
2017-12-01 15:06 ` [PATCH 5/6] dbus: Add convenient API for calling method on " Szymon Janc
2017-12-01 15:06 ` [PATCH 6/6] examples: Extend dbus-client example Szymon Janc
5 siblings, 0 replies; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 5584 bytes --]
l_dbus_proxy_set_property function allows to set properties via proxy
interface.
---
ell/dbus-client.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/dbus-client.h | 8 ++++
2 files changed, 121 insertions(+)
diff --git a/ell/dbus-client.c b/ell/dbus-client.c
index f07a183..0d69e4b 100644
--- a/ell/dbus-client.c
+++ b/ell/dbus-client.c
@@ -71,6 +71,7 @@ struct l_dbus_proxy {
bool ready;
struct l_queue *properties;
+ struct l_queue *pending_calls;
};
LIB_EXPORT const char *l_dbus_proxy_get_path(struct l_dbus_proxy *proxy)
@@ -153,6 +154,18 @@ static void property_free(void *data)
l_free(prop);
}
+static void cancel_pending_calls(struct l_dbus_proxy *proxy)
+{
+ const struct l_queue_entry *entry;
+
+ for (entry = l_queue_get_entries(proxy->pending_calls); entry;
+ entry = entry->next) {
+ uint32_t call_id = L_PTR_TO_UINT(entry->data);
+
+ l_dbus_cancel(proxy->client->dbus, call_id);
+ }
+}
+
static void l_dbus_proxy_destroy(struct l_dbus_proxy *proxy)
{
if (unlikely(!proxy))
@@ -162,12 +175,111 @@ static void l_dbus_proxy_destroy(struct l_dbus_proxy *proxy)
l_dbus_remove_signal_watch(proxy->client->dbus,
proxy->properties_watch);
+ cancel_pending_calls(proxy);
+ l_queue_destroy(proxy->pending_calls, NULL);
l_queue_destroy(proxy->properties, property_free);
l_free(proxy->interface);
l_free(proxy->path);
l_free(proxy);
}
+struct method_call_request
+{
+ struct l_dbus_proxy *proxy;
+ uint32_t call_id;
+ l_dbus_client_proxy_result_func_t result;
+ void *user_data;
+ l_dbus_destroy_func_t destroy;
+};
+
+static void method_call_request_free(void *user_data)
+{
+ struct method_call_request *req = user_data;
+
+ l_queue_remove(req->proxy->pending_calls, L_UINT_TO_PTR(req->call_id));
+
+ if (req->destroy)
+ req->destroy(req->user_data);
+
+ l_free(req);
+}
+
+static void method_call_reply(struct l_dbus_message *message, void *user_data)
+{
+ struct method_call_request *req = user_data;
+
+ if (req->result)
+ req->result(req->proxy, message, req->user_data);
+}
+
+LIB_EXPORT bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy,
+ l_dbus_client_proxy_result_func_t result,
+ void *user_data, l_dbus_destroy_func_t destroy,
+ const char *name, const char *signature, ...)
+{
+ struct l_dbus_client *client = proxy->client;
+ struct l_dbus_message_builder *builder;
+ struct method_call_request *req;
+ struct l_dbus_message *message;
+ struct proxy_property *prop;
+ va_list args;
+
+ if (unlikely(!proxy))
+ return false;
+
+ prop = find_property(proxy, name);
+ if (!prop)
+ return false;
+
+ if (strcmp(l_dbus_message_get_signature(prop->msg), signature))
+ return false;
+
+ message = l_dbus_message_new_method_call(client->dbus, client->service,
+ proxy->path,
+ L_DBUS_INTERFACE_PROPERTIES,
+ "Set");
+ if (!message)
+ return false;
+
+ builder = l_dbus_message_builder_new(message);
+ if (!builder) {
+ l_dbus_message_unref(message);
+ return false;
+ }
+
+ l_dbus_message_builder_append_basic(builder, 's', proxy->interface);
+ l_dbus_message_builder_append_basic(builder, 's', name);
+
+ l_dbus_message_builder_enter_variant(builder, signature);
+
+ va_start(args, signature);
+ l_dbus_message_builder_append_from_valist(builder, signature, args);
+ va_end(args);
+
+ l_dbus_message_builder_leave_variant(builder);
+
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ req = l_new(struct method_call_request, 1);
+ req->proxy = proxy;
+ req->result = result;
+ req->user_data = user_data;
+ req->destroy = destroy;
+
+ req->call_id = l_dbus_send_with_reply(client->dbus, message,
+ method_call_reply, req,
+ method_call_request_free);
+ if (!req->call_id) {
+ l_free(req);
+ return false;
+ }
+
+ l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id));
+
+ return true;
+}
+
static void proxy_update_property(struct l_dbus_proxy *proxy,
const char *name,
struct l_dbus_message_iter *property)
@@ -257,6 +369,7 @@ static struct l_dbus_proxy *l_dbus_proxy_new(struct l_dbus_client *client,
proxy->interface = l_strdup(interface);
proxy->path = l_strdup(path);
proxy->properties = l_queue_new();
+ proxy->pending_calls = l_queue_new();;
l_queue_push_tail(client->proxies, proxy);
diff --git a/ell/dbus-client.h b/ell/dbus-client.h
index 460c6c5..928dcec 100644
--- a/ell/dbus-client.h
+++ b/ell/dbus-client.h
@@ -39,6 +39,9 @@ typedef void (*l_dbus_client_ready_func_t)(struct l_dbus_client *client,
void *user_data);
typedef void (*l_dbus_client_proxy_func_t) (struct l_dbus_proxy *proxy,
void *user_data);
+typedef void (*l_dbus_client_proxy_result_func_t) (struct l_dbus_proxy *proxy,
+ struct l_dbus_message *result,
+ void *user_data);
typedef void (*l_dbus_client_property_function_t) (struct l_dbus_proxy *proxy,
const char *name,
struct l_dbus_message *msg,
@@ -75,6 +78,11 @@ const char *l_dbus_proxy_get_interface(struct l_dbus_proxy *proxy);
bool l_dbus_proxy_get_property(struct l_dbus_proxy *proxy, const char *name,
const char *signature, ...);
+
+bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy,
+ l_dbus_client_proxy_result_func_t result,
+ void *user_data, l_dbus_destroy_func_t destroy,
+ const char *name, const char *signature, ...);
#ifdef __cplusplus
}
#endif
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 5/6] dbus: Add convenient API for calling method on proxy interface
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
` (3 preceding siblings ...)
2017-12-01 15:06 ` [PATCH 4/6] dbus: Add support for setting properties on D-Bus " Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
2017-12-01 15:06 ` [PATCH 6/6] examples: Extend dbus-client example Szymon Janc
5 siblings, 0 replies; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 2116 bytes --]
This is wrapper around l_dbus_method_call that allows to cancel call
both by removed proxy and caller.
---
ell/dbus-client.c | 31 +++++++++++++++++++++++++++++++
ell/dbus-client.h | 8 ++++++++
2 files changed, 39 insertions(+)
diff --git a/ell/dbus-client.c b/ell/dbus-client.c
index 0d69e4b..5a48e52 100644
--- a/ell/dbus-client.c
+++ b/ell/dbus-client.c
@@ -280,6 +280,37 @@ LIB_EXPORT bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy,
return true;
}
+LIB_EXPORT uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy,
+ const char *method,
+ l_dbus_message_func_t setup,
+ l_dbus_client_proxy_result_func_t reply,
+ void *user_data,
+ l_dbus_destroy_func_t destroy)
+{
+ struct method_call_request *req;
+
+ req = l_new(struct method_call_request, 1);
+ req->proxy = proxy;
+ req->result = reply;
+ req->user_data = user_data;
+ req->destroy = destroy;
+
+ req->call_id = l_dbus_method_call(proxy->client->dbus,
+ proxy->client->service,
+ proxy->path, proxy->interface,
+ method, setup,
+ method_call_reply, req,
+ method_call_request_free);
+ if (!req->call_id) {
+ l_free(req);
+ return 0;
+ }
+
+ l_queue_push_tail(proxy->pending_calls, L_UINT_TO_PTR(req->call_id));
+
+ return req->call_id;
+}
+
static void proxy_update_property(struct l_dbus_proxy *proxy,
const char *name,
struct l_dbus_message_iter *property)
diff --git a/ell/dbus-client.h b/ell/dbus-client.h
index 928dcec..699d824 100644
--- a/ell/dbus-client.h
+++ b/ell/dbus-client.h
@@ -83,6 +83,14 @@ bool l_dbus_proxy_set_property(struct l_dbus_proxy *proxy,
l_dbus_client_proxy_result_func_t result,
void *user_data, l_dbus_destroy_func_t destroy,
const char *name, const char *signature, ...);
+
+uint32_t l_dbus_proxy_method_call(struct l_dbus_proxy *proxy,
+ const char *method,
+ l_dbus_message_func_t setup,
+ l_dbus_client_proxy_result_func_t reply,
+ void *user_data,
+ l_dbus_destroy_func_t destroy);
+
#ifdef __cplusplus
}
#endif
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 6/6] examples: Extend dbus-client example
2017-12-01 15:06 [PATCH 0/6] D-Bus client and proxy API Szymon Janc
` (4 preceding siblings ...)
2017-12-01 15:06 ` [PATCH 5/6] dbus: Add convenient API for calling method on " Szymon Janc
@ 2017-12-01 15:06 ` Szymon Janc
5 siblings, 0 replies; 11+ messages in thread
From: Szymon Janc @ 2017-12-01 15:06 UTC (permalink / raw)
To: ell
[-- Attachment #1: Type: text/plain, Size: 3791 bytes --]
This adds sample code for using D-Bus proxy interface.
---
examples/dbus-client.c | 93 +++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 84 insertions(+), 9 deletions(-)
diff --git a/examples/dbus-client.c b/examples/dbus-client.c
index 507a4e8..1f60643 100644
--- a/examples/dbus-client.c
+++ b/examples/dbus-client.c
@@ -60,23 +60,81 @@ static void disconnect_callback(void *user_data)
l_main_quit();
}
-static void service_appeared(struct l_dbus *dbus, void *user_data)
+static void iwd_service_appeared(struct l_dbus *dbus, void *user_data)
{
l_info("Service appeared");
}
-static void service_disappeared(struct l_dbus *dbus, void *user_data)
+static void iwd_service_disappeared(struct l_dbus *dbus, void *user_data)
{
- l_info("Service disappeared, quitting...");
- l_main_quit();
+ l_info("Service disappeared");
+}
+
+static void bluez_client_connected(struct l_dbus *dbus, void *user_data)
+{
+ l_info("client connected");
+}
+
+static void bluez_client_disconnected(struct l_dbus *dbus, void *user_data)
+{
+ l_info("client disconnected");
+}
+
+static void bluez_client_ready(struct l_dbus_client *client, void *user_data)
+{
+ l_info("client ready");
+}
+
+static void proxy_added(struct l_dbus_proxy *proxy, void *user_data)
+{
+ const char *interface = l_dbus_proxy_get_interface(proxy);
+ const char *path = l_dbus_proxy_get_path(proxy);
+
+ l_info("proxy added: %s %s", path, interface);
+
+ if (!strcmp(interface, "org.bluez.Adapter1") ||
+ !strcmp(interface, "org.bluez.Device1")) {
+ char *str;
+
+ if (!l_dbus_proxy_get_property(proxy, "Address", "s", &str))
+ return;
+
+ l_info(" Address: %s", str);
+ }
+}
+
+static void proxy_removed(struct l_dbus_proxy *proxy, void *user_data)
+{
+ l_info("proxy removed: %s %s", l_dbus_proxy_get_path(proxy),
+ l_dbus_proxy_get_interface(proxy));
+}
+
+static void property_changed(struct l_dbus_proxy *proxy, const char *name,
+ struct l_dbus_message *msg, void *user_data)
+{
+ l_info("property changed: %s (%s %s)", name,
+ l_dbus_proxy_get_path(proxy),
+ l_dbus_proxy_get_interface(proxy));
+
+ if (!strcmp(name, "Address")) {
+ char *str;
+
+ if (!l_dbus_message_get_arguments(msg, "s", &str)) {
+ return;
+ }
+
+ l_info(" Address: %s", str);
+ }
}
int main(int argc, char *argv[])
{
+ struct l_dbus_client *client;
struct l_dbus *dbus;
struct l_signal *signal;
sigset_t mask;
- uint32_t watch_id;
+ uint32_t iwd_watch_id;
+
if (!l_main_init())
return -1;
@@ -93,14 +151,31 @@ int main(int argc, char *argv[])
l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
- watch_id = l_dbus_add_service_watch(dbus, "net.connman.iwd",
- service_appeared,
- service_disappeared,
+ /* service basic watch */
+ iwd_watch_id = l_dbus_add_service_watch(dbus, "net.connman.iwd",
+ iwd_service_appeared,
+ iwd_service_disappeared,
NULL, NULL);
+ /* proxy example */
+ client = l_dbus_client_new(dbus, "org.bluez", "/org/bluez");
+
+ l_dbus_client_set_connect_handler(client, bluez_client_connected, NULL,
+ NULL);
+ l_dbus_client_set_disconnect_handler(client, bluez_client_disconnected,
+ NULL, NULL);
+
+ l_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+ property_changed, NULL, NULL);
+
+ l_dbus_client_set_ready_handler(client, bluez_client_ready, NULL, NULL);
+
+
l_main_run();
- l_dbus_remove_watch(dbus, watch_id);
+ l_dbus_remove_watch(dbus, iwd_watch_id);
+
+ l_dbus_client_destroy(client);
l_dbus_destroy(dbus);
l_signal_remove(signal);
--
2.14.3
^ permalink raw reply related [flat|nested] 11+ messages in thread