From f35ba2e4b28768ab3f6a07403a3bd360162094ed Mon Sep 17 00:00:00 2001 From: Mark Doffman Date: Sat, 7 Nov 2009 17:49:15 +0000 Subject: [PATCH] Add the droute and dbind libraries as static libraries within this repository. Previously these were shared libraries in at-spi2-core. --- Makefile.am | 2 +- README | 16 ++ atk-adaptor/Makefile.am | 2 + atk-adaptor/accessible-adaptor.c | 24 +- common/Makefile.am | 27 +- configure.ac | 24 +- cspi/Makefile.am | 2 + dbind/Makefile.am | 22 ++ dbind/dbind-any.c | 553 ++++++++++++++++++++++++++++++++++++ dbind/dbind-any.h | 31 ++ dbind/dbind.c | 230 +++++++++++++++ dbind/dbind.h | 46 +++ dbind/dbtest.c | 403 ++++++++++++++++++++++++++ droute/Makefile.am | 28 ++ droute/droute-pairhash.c | 87 ++++++ droute/droute-pairhash.h | 41 +++ droute/droute-test.c | 243 ++++++++++++++++ droute/droute-variant.c | 118 ++++++++ droute/droute-variant.h | 35 +++ droute/droute.c | 598 +++++++++++++++++++++++++++++++++++++++ droute/droute.h | 95 +++++++ droute/test.interface.One | 15 + droute/test.interface.Two | 15 + 23 files changed, 2621 insertions(+), 36 deletions(-) create mode 100644 dbind/Makefile.am create mode 100644 dbind/dbind-any.c create mode 100644 dbind/dbind-any.h create mode 100644 dbind/dbind.c create mode 100644 dbind/dbind.h create mode 100644 dbind/dbtest.c create mode 100644 droute/Makefile.am create mode 100644 droute/droute-pairhash.c create mode 100644 droute/droute-pairhash.h create mode 100644 droute/droute-test.c create mode 100644 droute/droute-variant.c create mode 100644 droute/droute-variant.h create mode 100644 droute/droute.c create mode 100644 droute/droute.h create mode 100644 droute/test.interface.One create mode 100644 droute/test.interface.Two diff --git a/Makefile.am b/Makefile.am index a05ffab..305d97d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1 +1 @@ -SUBDIRS=common atk-adaptor tests +SUBDIRS=droute dbind common atk-adaptor tests diff --git a/README b/README index 5fb501f..21e57d0 100644 --- a/README +++ b/README @@ -69,6 +69,22 @@ The directories within this package are arranged as follows: the ATK adaptor and 'Cspi'. Structures are mainly related to events. + droute + + Contains a framework for registering objects + with a D-Bus connection and for routing messages to + the implementing object. + + Used by the ATK adaptor. + + dbind + + Library to ease making D-Bus method calls, contains + marshalling code to convert function arguments + and a provided D-Bus signature into a D-Bus message. + + Used by cspi. + atk-adaptor This directory contains code that bridges diff --git a/atk-adaptor/Makefile.am b/atk-adaptor/Makefile.am index 5d89a2d..f345355 100644 --- a/atk-adaptor/Makefile.am +++ b/atk-adaptor/Makefile.am @@ -21,6 +21,8 @@ libatk_bridge_la_LIBADD = $(DBUS_GLIB_LIBS) \ $(ATK_LIBS) \ $(DBIND_LIBS) \ $(DROUTE_LIBS) \ + $(top_builddir)/droute/libdroute.la \ + $(top_builddir)/dbind/libdbind.la \ $(top_builddir)/common/libspicommon.la libatk_bridge_la_SOURCES = \ diff --git a/atk-adaptor/accessible-adaptor.c b/atk-adaptor/accessible-adaptor.c index c59f39e..1940d9b 100644 --- a/atk-adaptor/accessible-adaptor.c +++ b/atk-adaptor/accessible-adaptor.c @@ -495,19 +495,27 @@ impl_getState (DBusConnection *bus, void *user_data) { AtkObject *object = (AtkObject *) user_data; - dbus_uint32_t rv[2]; - dbus_uint32_t *array = rv; - DBusMessage *reply; + + DBusMessage *reply = NULL; + DBusMessageIter iter, iter_array; + + dbus_uint32_t states [2]; + + guint count; g_return_val_if_fail (ATK_IS_OBJECT (user_data), droute_not_yet_handled_error (message)); - spi_atk_state_to_dbus_array (object, rv); + reply = dbus_message_new_method_return (message); - if (reply) + dbus_message_iter_init_append (reply, &iter); + + spi_atk_state_to_dbus_array (object, states); + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "u", &iter_array); + for (count = 0; count < 2; count++) { - dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array, - 2, DBUS_TYPE_INVALID); + dbus_message_iter_append_basic (&iter_array, DBUS_TYPE_UINT32, &states[count]); } + dbus_message_iter_close_container (&iter, &iter_array); return reply; } @@ -517,7 +525,7 @@ impl_getAttributes (DBusConnection *bus, void *user_data) { AtkObject *object = (AtkObject *) user_data; - DBusMessage *reply; + DBusMessage *reply = NULL; AtkAttributeSet *attributes; DBusMessageIter iter; diff --git a/common/Makefile.am b/common/Makefile.am index cbf5671..066c30c 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -8,30 +8,19 @@ libspicommon_la_CFLAGS = $(DBUS_GLIB_CFLAGS)\ libspicommon_la_LIBADD = $(DBUS_GLIB_LIBS) -#spicommonincludedir = $(includedir)/at-spi-1.0/libspi -# -#spicommoninclude_HEADERS = \ -# bitarray.h \ -# event-types.h \ -# generated-types.h \ -# keymasks.h \ -# spi-dbus.h \ -# spi-stateset.h \ -# spi-types.h - -#BUILT_SOURCES = generated-types.h -#CLEANFILES = generated-types.h - -nodist_libspicommon_la_SOURCES = generated-types.h - libspicommon_la_SOURCES = \ - bitarray.h \ + bitarray.h \ + keymasks.h \ + generated-types.h \ event-types.h \ spi-types.h \ spi-dbus.h \ - spi-dbus.c \ - spi-stateset.h \ + spi-dbus.c \ + spi-stateset.h \ spi-stateset.c +#BUILT_SOURCES = generated-types.h +#CLEANFILES = generated-types.h + #generated-types.h: $(top_srcdir)/xml/spec.xml $(top_srcdir)/tools/c-constants-generator.xsl # xsltproc --stringparam mixed-case-prefix Accessibility_ $(top_srcdir)/tools/c-constants-generator.xsl $< >$@ diff --git a/configure.ac b/configure.ac index 81e2af0..e27f605 100644 --- a/configure.ac +++ b/configure.ac @@ -33,14 +33,6 @@ PKG_CHECK_MODULES(DBUS, [dbus-1 >= 1.0]) AC_SUBST(DBUS_LIBS) AC_SUBST(DBUS_CFLAGS) -PKG_CHECK_MODULES(DROUTE, [droute-0.1 >= 0.1]) -AC_SUBST(DROUTE_LIBS) -AC_SUBST(DROUTE_CFLAGS) - -PKG_CHECK_MODULES(DBIND, [dbind-0.1 >= 0.1]) -AC_SUBST(DBIND_LIBS) -AC_SUBST(DBIND_CFLAGS) - PKG_CHECK_MODULES(GLIB, [glib-2.0]) AC_SUBST(GLIB_LIBS) AC_SUBST(GLIB_CFLAGS) @@ -98,7 +90,23 @@ else fi AC_SUBST(EXTRA_SOCKET_LIBS) +dnl find sizes & alignments +orig_CPPFLAGS=$CPPFLAGS +CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS" +DBIND_CHECK_ALIGNOF(char) +DBIND_CHECK_ALIGNOF(dbus_bool_t) +DBIND_CHECK_ALIGNOF(dbus_int16_t) +DBIND_CHECK_ALIGNOF(dbus_int32_t) +DBIND_CHECK_ALIGNOF(dbus_int64_t) +DBIND_CHECK_ALIGNOF(double) +DBIND_CHECK_ALIGNOF(dbind_pointer) +DBIND_CHECK_ALIGNOF(dbind_struct) +CPPFLAGS=$orig_CPPFLAGS + AC_CONFIG_FILES([Makefile + droute/Makefile + dbind/Makefile + dbind/dbind-config.h common/Makefile atk-adaptor/Makefile tests/Makefile diff --git a/cspi/Makefile.am b/cspi/Makefile.am index 2ce79ef..49a56e6 100644 --- a/cspi/Makefile.am +++ b/cspi/Makefile.am @@ -44,4 +44,6 @@ libcspi_la_LIBADD = \ $(X_LIBS) \ $(DBUS_GLIB_LIBS) \ $(ATK_LIBS) \ + $(top_builddir)/droute/libdbind.la \ + $(top_builddir)/droute/libdroute.la \ $(top_builddir)/common/libspicommon.la diff --git a/dbind/Makefile.am b/dbind/Makefile.am new file mode 100644 index 0000000..f7e6f53 --- /dev/null +++ b/dbind/Makefile.am @@ -0,0 +1,22 @@ +noinst_LTLIBRARIES = libdbind.la + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"dbind\" \ + -I$(top_srcdir) \ + $(WARN_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) + +libdbind_la_SOURCES = \ + dbind-config.h \ + dbind.h \ + dbind.c \ + dbind-any.h \ + dbind-any.c +libdbind_la_LIBADD = $(DBUS_LIBS) $(GLIB_LIBS) + +TESTS = dbtest + +check_PROGRAMS = dbtest +dbtest_SOURCES = dbtest.c +dbtest_LDFLAGS = libdbind.la diff --git a/dbind/dbind-any.c b/dbind/dbind-any.c new file mode 100644 index 0000000..79a8832 --- /dev/null +++ b/dbind/dbind-any.c @@ -0,0 +1,553 @@ +/* type driven marshalling */ +#include +#include + +#include "config.h" +#include "dbind-config.h" +#include "dbind-any.h" + +#undef DEBUG + +/* Align a value upward to a boundary, expressed as a number of bytes. + * E.g. align to an 8-byte boundary with argument of 8. + * + * (this + boundary - 1) + * & + * ~(boundary - 1) + */ +#define ALIGN_VALUE(this, boundary) \ + (( ((gulong)(this)) + (((gulong)(boundary)) -1)) & (~(((gulong)(boundary))-1))) + +#define ALIGN_ADDRESS(this, boundary) \ + ((gpointer)ALIGN_VALUE(this, boundary)) + +#define PTR_PLUS(ptr, offset) \ + ((gpointer) (((guchar *)(ptr)) + (offset))) + +#define DBIND_POD_CASES \ + DBUS_TYPE_BYTE: \ + case DBUS_TYPE_INT16: \ + case DBUS_TYPE_UINT16: \ + case DBUS_TYPE_INT32: \ + case DBUS_TYPE_UINT32: \ + case DBUS_TYPE_BOOLEAN: \ + case DBUS_TYPE_INT64: \ + case DBUS_TYPE_UINT64: \ + case DBUS_TYPE_DOUBLE + +/*---------------------------------------------------------------------------*/ + +static void +warn_braces () +{ + fprintf (stderr, "Error: dbus flags structures & dicts with braces rather than " + " an explicit type member of 'struct'\n"); +} + +/*---------------------------------------------------------------------------*/ + +static unsigned int +dbind_find_c_alignment_r (char **type) +{ + unsigned int retval = 1; + + char t = **type; + (*type)++; + +#ifdef DEBUG + fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t); +#endif + + switch (t) { + case DBUS_TYPE_BYTE: + return DBIND_ALIGNOF_CHAR; + case DBUS_TYPE_BOOLEAN: + return DBIND_ALIGNOF_DBUS_BOOL_T; + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return DBIND_ALIGNOF_DBUS_INT16_T; + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + return DBIND_ALIGNOF_DBUS_INT32_T; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + return DBIND_ALIGNOF_DBUS_INT64_T; + case DBUS_TYPE_DOUBLE: + return DBIND_ALIGNOF_DOUBLE; + /* ptr types */ + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + case DBUS_TYPE_ARRAY: + return DBIND_ALIGNOF_DBIND_POINTER; + case DBUS_STRUCT_BEGIN_CHAR: +#if DBIND_ALIGNOF_DBIND_STRUCT > 1 + retval = MAX (retval, DBIND_ALIGNOF_DBIND_STRUCT); +#endif + while (**type != DBUS_STRUCT_END_CHAR) { + int elem_align = dbind_find_c_alignment_r (type); + retval = MAX (retval, elem_align); + } + (*type)++; + return retval; + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + warn_braces (); + return DBIND_ALIGNOF_DBIND_POINTER; + case '\0': + g_assert_not_reached(); + break; + default: + return 1; + } +} + +/*---------------------------------------------------------------------------*/ + +/* gather immediate allocation information for this type */ +static size_t +dbind_gather_alloc_info_r (char **type) +{ + char t = **type; + (*type)++; + if (t == DBUS_TYPE_ARRAY) + { + switch (**type) + { + case DBUS_STRUCT_BEGIN_CHAR: + while (**type != DBUS_STRUCT_END_CHAR && **type != '\0') (*type)++; + if (**type != '\0') (*type)++; + break; + case '\0': + break; + default: + (*type)++; + break; + } + } + + switch (t) { + case DBUS_TYPE_BYTE: + return sizeof (char); + case DBUS_TYPE_BOOLEAN: + return sizeof (dbus_bool_t); + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + return sizeof (dbus_int16_t); + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + return sizeof (dbus_int32_t); + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + return sizeof (dbus_int64_t); + case DBUS_TYPE_DOUBLE: + return sizeof (double); + /* ptr types */ + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + case DBUS_TYPE_ARRAY: + return sizeof (void *); + case DBUS_STRUCT_BEGIN_CHAR: { + int sum = 0, stralign; + + stralign = dbind_find_c_alignment (*type - 1); + + while (**type != DBUS_STRUCT_END_CHAR) { + sum = ALIGN_VALUE (sum, dbind_find_c_alignment (*type)); + sum += dbind_gather_alloc_info_r (type); + } + sum = ALIGN_VALUE (sum, stralign); + + g_assert (**type == DBUS_STRUCT_END_CHAR); + (*type)++; + + return sum; + } + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + warn_braces (); + default: + return 0; + } +} + +static size_t +dbind_gather_alloc_info (char *type) +{ + return dbind_gather_alloc_info_r (&type); +} + +/*---------------------------------------------------------------------------*/ + +static void +dbind_any_free_r (char **type, void **data) +{ +#ifdef DEBUG + fprintf (stderr, "any free '%c' to %p\n", **type, *data); +#endif + + switch (**type) { + case DBIND_POD_CASES: + *data = ((guchar *)*data) + dbind_gather_alloc_info (*type); + (*type)++; + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: +#ifdef DEBUG + fprintf (stderr, "string free %p\n", **(void ***)data); +#endif + g_free (**(void ***)data); + *data = ((guchar *)*data) + dbind_gather_alloc_info (*type); + (*type)++; + break; + case DBUS_TYPE_ARRAY: { + int i; + GArray *vals = **(void ***)data; + size_t elem_size, elem_align; + char *saved_child_type; + + (*type)++; + saved_child_type = *type; + + elem_size = dbind_gather_alloc_info (*type); + elem_align = dbind_find_c_alignment_r (type); + + for (i = 0; i < vals->len; i++) { + void *ptr = vals->data + elem_size * i; + *type = saved_child_type; /* rewind type info */ + ptr = ALIGN_ADDRESS (ptr, elem_align); + dbind_any_free_r (type, &ptr); + } + g_array_free (vals, TRUE); + break; + } + case DBUS_STRUCT_BEGIN_CHAR: { + gconstpointer data0 = *data; + int offset = 0, stralign; + + stralign = dbind_find_c_alignment (*type); + (*type)++; + + offset = 0 ; + while (**type != DBUS_STRUCT_END_CHAR) { + char *subt = *type; + offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type)); + *data = PTR_PLUS (data0, offset); + dbind_any_free_r (type, data); + offset += dbind_gather_alloc_info (subt); + } + + offset = ALIGN_VALUE (offset, stralign); + *data = PTR_PLUS (data0, offset); + + g_assert (**type == DBUS_STRUCT_END_CHAR); + (*type)++; + + break; + } + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + warn_braces (); + break; + } +} + +/*---------------------------------------------------------------------------*/ + +void +dbind_any_marshal (DBusMessageIter *iter, + char **type, + void **data) +{ + size_t len; + +#ifdef DEBUG + fprintf (stderr, "any marshal '%c' to %p\n", **type, *data); +#endif + + switch (**type) { + case DBIND_POD_CASES: + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + len = dbind_gather_alloc_info (*type); + dbus_message_iter_append_basic (iter, **type, *data); + *data = ((guchar *)*data) + len; + (*type)++; + break; + case DBUS_TYPE_ARRAY: { + int i; + GArray *vals = **(void ***)data; + size_t elem_size, elem_align; + DBusMessageIter sub; + char *saved_child_type, *child_type_string; + + (*type)++; + saved_child_type = *type; + + elem_size = dbind_gather_alloc_info (*type); + elem_align = dbind_find_c_alignment_r (type); + + /* wow this part of the API sucks too ... */ + child_type_string = g_strndup (saved_child_type, *type - saved_child_type); + /* fprintf (stderr, "array child type '%s'\n", child_type_string); */ + dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY, + child_type_string, &sub); + for (i = 0; i < vals->len; i++) { + void *ptr = vals->data + elem_size * i; + *type = saved_child_type; /* rewind type info */ + ptr = ALIGN_ADDRESS (ptr, elem_align); + dbind_any_marshal (&sub, type, &ptr); + } + + dbus_message_iter_close_container (iter, &sub); + g_free (child_type_string); + break; + } + case DBUS_STRUCT_BEGIN_CHAR: { + gconstpointer data0 = *data; + int offset = 0, stralign; + DBusMessageIter sub; + + stralign = dbind_find_c_alignment (*type); + + (*type)++; + + dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT, NULL, &sub); + + offset = 0 ; + while (**type != DBUS_STRUCT_END_CHAR) { + char *subt = *type; + offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type)); + *data = PTR_PLUS (data0, offset); + dbind_any_marshal (&sub, type, data); + offset += dbind_gather_alloc_info (subt); + } + + offset = ALIGN_VALUE (offset, stralign); + *data = PTR_PLUS (data0, offset); + + dbus_message_iter_close_container (iter, &sub); + + g_assert (**type == DBUS_STRUCT_END_CHAR); + (*type)++; + + break; + } + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + warn_braces (); + break; + } +} + +/*---------------------------------------------------------------------------*/ + +void +dbind_any_marshal_va (DBusMessageIter *iter, + char **arg_types, + va_list args) +{ + char *p = *arg_types; + + /* Guard against null arg types + Fix for - http://bugs.freedesktop.org/show_bug.cgi?id=23027 + */ + if (p == NULL) + p = ""; + + { + /* special case base-types since we need to walk the stack worse-luck */ + for (;*p != '\0' && *p != '=';) { + int intarg; + void *ptrarg; + double doublearg; + dbus_int64_t int64arg; + void *arg = NULL; + + switch (*p) { + case DBUS_TYPE_BYTE: + case DBUS_TYPE_BOOLEAN: + case DBUS_TYPE_INT16: + case DBUS_TYPE_UINT16: + case DBUS_TYPE_INT32: + case DBUS_TYPE_UINT32: + intarg = va_arg (args, int); + arg = &intarg; + break; + case DBUS_TYPE_INT64: + case DBUS_TYPE_UINT64: + int64arg = va_arg (args, dbus_int64_t); + arg = &int64arg; + break; + case DBUS_TYPE_DOUBLE: + doublearg = va_arg (args, double); + arg = &doublearg; + break; + /* ptr types */ + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + case DBUS_TYPE_ARRAY: + case DBUS_TYPE_DICT_ENTRY: + ptrarg = va_arg (args, void *); + arg = &ptrarg; + break; + case DBUS_STRUCT_BEGIN_CHAR: + ptrarg = va_arg (args, void *); + arg = ptrarg; + break; + + case DBUS_TYPE_VARIANT: + fprintf (stderr, "No variant support yet - very toolkit specific\n"); + ptrarg = va_arg (args, void *); + arg = &ptrarg; + break; + default: + fprintf (stderr, "Unknown / invalid arg type %c\n", *p); + break; + } + if (arg != NULL) + dbind_any_marshal (iter, &p, &arg); + } + } +} + +/*---------------------------------------------------------------------------*/ + +void +dbind_any_demarshal (DBusMessageIter *iter, + char **type, + void **data) +{ + size_t len; + +#ifdef DEBUG + fprintf (stderr, "any demarshal '%c' to %p\n", **type, *data); +#endif + + switch (**type) { + case DBIND_POD_CASES: + len = dbind_gather_alloc_info (*type); + dbus_message_iter_get_basic (iter, *data); + *data = ((guchar *)*data) + len; + (*type)++; + break; + case DBUS_TYPE_STRING: + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_SIGNATURE: + len = dbind_gather_alloc_info (*type); + dbus_message_iter_get_basic (iter, *data); +#ifdef DEBUG + fprintf (stderr, "dup string '%s' (%p)\n", **(void ***)data, **(void ***)data); +#endif + **(void ***)data = g_strdup (**(void ***)data); + *data = ((guchar *)*data) + len; + (*type)++; + break; + case DBUS_TYPE_ARRAY: { + GArray *vals; + DBusMessageIter child; + size_t elem_size, elem_align; + char *stored_child_type; + int i; + + (*type)++; + stored_child_type = *type; + + elem_size = dbind_gather_alloc_info (*type); + elem_align = dbind_find_c_alignment_r (type); + vals = g_array_new (FALSE, FALSE, elem_size); + (**(void ***)data) = vals; + *data = ((guchar *)*data) + sizeof (void *); + + i = 0; + dbus_message_iter_recurse (iter, &child); + while (dbus_message_iter_get_arg_type (&child) != DBUS_TYPE_INVALID) { + void *ptr; + char *subt = stored_child_type; + g_array_set_size (vals, i + 1); + ptr = vals->data + elem_size * i; + ptr = ALIGN_ADDRESS (ptr, elem_align); + dbind_any_demarshal (&child, &subt, &ptr); + i++; + }; + break; + } + case DBUS_STRUCT_BEGIN_CHAR: { + gconstpointer data0 = *data; + int offset = 0, stralign; + DBusMessageIter child; + + stralign = dbind_find_c_alignment (*type); + + (*type)++; + + dbus_message_iter_recurse (iter, &child); + + while (**type != DBUS_STRUCT_END_CHAR) { + char *subt = *type; + offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type)); + *data = PTR_PLUS (data0, offset); + dbind_any_demarshal (&child, type, data); + offset += dbind_gather_alloc_info (subt); + } + + offset = ALIGN_VALUE (offset, stralign); + *data = PTR_PLUS (data0, offset); + + g_assert (**type == DBUS_STRUCT_END_CHAR); + (*type)++; + + break; + } + case DBUS_TYPE_STRUCT: + case DBUS_TYPE_DICT_ENTRY: + warn_braces (); + break; + } + dbus_message_iter_next (iter); +} + +/*---------------------------------------------------------------------------*/ + +void +dbind_any_demarshal_va (DBusMessageIter *iter, + char **arg_types, + va_list args) +{ + char *p = *arg_types; + for (;*p != '\0';) { + void *arg = va_arg (args, void *); + dbind_any_demarshal (iter, &p, &arg); + } +} + +/*---------------------------------------------------------------------------*/ + +/* nice deep free ... */ +void +dbind_any_free (char *type, + void *ptr) +{ + dbind_any_free_r (&type, &ptr); +} + +/* should this be the default normalization ? */ +void +dbind_any_free_ptr (char *type, void *ptr) +{ + dbind_any_free (type, &ptr); +} + +/*---------------------------------------------------------------------------*/ + +unsigned int +dbind_find_c_alignment (char *type) +{ + return dbind_find_c_alignment_r (&type); +} + +/*END------------------------------------------------------------------------*/ diff --git a/dbind/dbind-any.h b/dbind/dbind-any.h new file mode 100644 index 0000000..975b244 --- /dev/null +++ b/dbind/dbind-any.h @@ -0,0 +1,31 @@ +#ifndef _DBIND_ANY_H_ +#define _DBIND_ANY_H_ + +#define DBUS_API_SUBJECT_TO_CHANGE +#include + +unsigned int dbind_find_c_alignment (char *type); + +void dbind_any_marshal (DBusMessageIter *iter, + char **type, + void **val); + +void dbind_any_marshal_va (DBusMessageIter *iter, + char **arg_types, + va_list args); + +void dbind_any_demarshal (DBusMessageIter *iter, + char **type, + void **val); + +void dbind_any_demarshal_va (DBusMessageIter *iter, + char **arg_types, + va_list args); + +void dbind_any_free (char *type, + void *ptr_to_ptr); + +void dbind_any_free_ptr (char *type, + void *ptr); + +#endif /* _DBIND_ANY_H_ */ diff --git a/dbind/dbind.c b/dbind/dbind.c new file mode 100644 index 0000000..f405888 --- /dev/null +++ b/dbind/dbind.c @@ -0,0 +1,230 @@ + + +#include +#include +#include + +#include "config.h" +#include "dbind/dbind.h" + +/* + * FIXME: compare types - to ensure they match & + * do dynamic padding of structures etc. + */ + +/*---------------------------------------------------------------------------*/ + +static void +set_reply (DBusPendingCall *pending, void *user_data) +{ + void **replyptr = (void **)user_data; + + *replyptr = dbus_pending_call_steal_reply (pending); +} + +static DBusMessage * +send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error) +{ + DBusPendingCall *pending; + DBusMessage *reply = NULL; + + if (!dbus_connection_send_with_reply (bus, message, &pending, -1)) + { + return NULL; + } + dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL); + while (!reply) + { + if (!dbus_connection_read_write_dispatch (bus, -1)) return NULL; + } + return reply; +} + +dbus_bool_t +dbind_method_call_reentrant_va (DBusConnection *cnx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + va_list args) +{ + dbus_bool_t success = FALSE; + DBusMessage *msg = NULL, *reply = NULL; + DBusMessageIter iter; + DBusError *err, real_err; + const char *p; + + if (opt_error) + err = opt_error; + else { + dbus_error_init (&real_err); + err = &real_err; + } + + msg = dbus_message_new_method_call (bus_name, path, interface, method); + if (!msg) + goto out; + + p = arg_types; + dbus_message_iter_init_append (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); + + reply = send_and_allow_reentry (cnx, msg, err); + if (!reply) + goto out; + + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + const char *name = dbus_message_get_error_name (reply); + dbus_set_error (err, name, g_strdup ("")); + goto out; + } + /* demarshal */ + if (p[0] == '=' && p[1] == '>') + { + DBusMessageIter iter; + p += 2; + dbus_message_iter_init (reply, &iter); + dbind_any_demarshal_va (&iter, &p, args); + } + + success = TRUE; +out: + if (msg) + dbus_message_unref (msg); + + if (reply) + dbus_message_unref (reply); + + if (err == &real_err) + dbus_error_free (err); + + return success; +} + +/** + * dbind_method_call_reentrant: + * + * @cnx: A D-Bus Connection used to make the method call. + * @bus_name: The D-Bus bus name of the program where the method call should + * be made. + * @path: The D-Bus object path that should handle the method. + * @interface: The D-Bus interface used to scope the method name. + * @method: Method to be invoked. + * @opt_error: D-Bus error. + * @arg_types: Variable length arguments interleaving D-Bus argument types + * and pointers to argument data. + * + * Makes a D-Bus method call using the supplied location data, method name and + * argument data.This function is re-entrant. It continuously reads from the D-Bus + * bus and dispatches messages until a reply has been recieved. + **/ +dbus_bool_t +dbind_method_call_reentrant (DBusConnection *cnx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + ...) +{ + dbus_bool_t success = FALSE; + va_list args; + + va_start (args, arg_types); + success = dbind_method_call_reentrant_va (cnx, + bus_name, + path, + interface, + method, + opt_error, + arg_types, + args); + va_end (args); + + return success; +} + +/*---------------------------------------------------------------------------*/ + +dbus_bool_t +dbind_emit_signal_va (DBusConnection *cnx, + const char *path, + const char *interface, + const char *signal, + DBusError *opt_error, + const char *arg_types, + va_list args) +{ + dbus_bool_t success = FALSE; + DBusMessage *msg = NULL; + DBusMessageIter iter; + DBusError *err, real_err; + char *p; + + if (opt_error) + err = opt_error; + else { + dbus_error_init (&real_err); + err = &real_err; + } + + msg = dbus_message_new_signal (path, interface, signal); + if (!msg) + goto out; + + p = arg_types; + dbus_message_iter_init_append (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); + + if (!dbus_connection_send (cnx, msg, NULL)) + goto out; + + success = TRUE; +out: + + if (msg) + dbus_message_unref (msg); + + if (err == &real_err) + dbus_error_free (err); + + return success; +} + +/** + * dbind_emit_signal: + * + * @cnx: A D-Bus Connection used to make the method call. + * @path: The D-Bus object path that this signal is emitted from. + * @interface: The D-Bus interface used to scope the method name. + * @signal: Name of signal to emit. + * @opt_error: D-Bus error. + * @arg_types: Variable length arguments interleaving D-Bus argument types + * and pointers to argument data. + * + * Emits a D-Bus signal using the supplied signal name and argument data. + **/ +dbus_bool_t +dbind_emit_signal (DBusConnection *cnx, + const char *path, + const char *interface, + const char *signal, + DBusError *opt_error, + const char *arg_types, + ...) +{ + dbus_bool_t success = FALSE; + va_list args; + + va_start (args, arg_types); + success = dbind_emit_signal_va (cnx, path, interface, signal, opt_error, arg_types, args); + va_end (args); + + return success; +} + +/*END------------------------------------------------------------------------*/ diff --git a/dbind/dbind.h b/dbind/dbind.h new file mode 100644 index 0000000..cc318c4 --- /dev/null +++ b/dbind/dbind.h @@ -0,0 +1,46 @@ +#ifndef _DBIND_H_ +#define _DBIND_H_ + +#define DBUS_API_SUBJECT_TO_CHANGE +#include +#include + +dbus_bool_t +dbind_method_call_reentrant_va (DBusConnection *cnx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + va_list args); + +dbus_bool_t +dbind_method_call_reentrant (DBusConnection *cnx, + const char *bus_name, + const char *path, + const char *interface, + const char *method, + DBusError *opt_error, + const char *arg_types, + ...); + +dbus_bool_t +dbind_emit_signal_va (DBusConnection *cnx, + const char *path, + const char *interface, + const char *signal, + DBusError *opt_error, + const char *arg_types, + va_list args); + +dbus_bool_t +dbind_emit_signal (DBusConnection *cnx, + const char *path, + const char *interface, + const char *signal, + DBusError *opt_error, + const char *arg_types, + ...); + +#endif /* _DBIND_H_ */ diff --git a/dbind/dbtest.c b/dbind/dbtest.c new file mode 100644 index 0000000..d00486a --- /dev/null +++ b/dbind/dbtest.c @@ -0,0 +1,403 @@ +#include +#include +#include +#include + +/* Wow! dbus is unpleasant to use */ + +#define DESKICE_PATH "/Novell/ICEDesktop/Daemon" +#define DESKICE_NAMESPACE "Novell.ICEDesktop.Daemon" + +void marshal (DBusMessage *msg, char *type, void *ptr) +{ + DBusMessageIter iter; + + dbus_message_iter_init_append (msg, &iter); + dbind_any_marshal (&iter, &type, &ptr); +} + +void demarshal (DBusMessage *msg, char *type, void *ptr) +{ + DBusMessageIter iter; + + if (!dbus_message_iter_init (msg, &iter)) + fprintf (stderr, "no data in msg\n"); + else + dbind_any_demarshal (&iter, &type, &ptr); +} + +#if 0 +dbus_bool_t dbus_message_marshal (DBusMessage *msg, + char **marshalled_data_p, + int *len_p); + +void dump_msg (DBusMessage *msg) +{ + char *data = NULL; + int len, i, j; + + dbus_message_marshal (msg, &data, &len); + for (i = 0; i < (len+15)/16; i++) { + fprintf (stderr, "%4.d | ", i * 16); + for (j = 0; j < 16; j++) { + unsigned char c = (i*16+j <= len) ? data[i*16+j] : 0; + fprintf (stderr, "0x%.2x ", c); + } + fprintf (stderr, " | "); + for (j = 0; j < 16; j++) { + char c = (i*16+j <= len) ? data[i*16+j] : '\0'; + fprintf (stderr, "%c", g_ascii_isprint (c) ? c : '.'); + } + } +} +#endif + +void test_simple () +{ + dbus_int32_t v1, v2; + DBusMessage *msg; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + v1 = 42; + marshal (msg, "i", &v1); + demarshal (msg, "i", &v2); + g_assert (v2 == 42); + g_assert (v1 == v2); + + dbind_any_free ("i", &v2); /* nop */ + dbus_message_unref (msg); + + fprintf (stderr, "simple ok\n"); +} + +void test_array () +{ + GArray *a1, *a2; + DBusMessage *msg; + + /* pod types */ + a1 = g_array_new (FALSE, FALSE, sizeof (dbus_int32_t)); + g_array_set_size (a1, 4); + g_array_index (a1, dbus_int32_t, 0) = 42; + g_array_index (a1, dbus_int32_t, 1) = 17; + g_array_index (a1, dbus_int32_t, 2) = 26; + g_array_index (a1, dbus_int32_t, 3) = 38; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + marshal (msg, "ai", &a1); + demarshal (msg, "ai", &a2); + + g_assert (a2 != NULL); + g_assert (a2->len == 4); + g_assert (g_array_index (a2, dbus_int32_t, 0) == 42); + g_assert (g_array_index (a2, dbus_int32_t, 1) == 17); + g_assert (g_array_index (a2, dbus_int32_t, 2) == 26); + g_assert (g_array_index (a2, dbus_int32_t, 3) == 38); + g_array_free (a1, TRUE); + + dbind_any_free ("ai", &a2); + dbus_message_unref (msg); + + fprintf (stderr, "array ok\n"); +} + +/* this taught me that the struct type is a mis-nomer, + it is generated by brackets */ +void test_struct_native () +{ + DBusMessage *msg; + DBusMessageIter iter, arr, str; + + /* manually create ar(ss) */ + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + + dbus_message_iter_init_append (msg, &iter); + + dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "(ss)", &arr); + { + char *foo; + dbus_message_iter_open_container (&arr, DBUS_TYPE_STRUCT, NULL, &str); + + foo = "foo"; + dbus_message_iter_append_basic (&str, DBUS_TYPE_STRING, &foo); + foo = "baa"; + dbus_message_iter_append_basic (&str, DBUS_TYPE_STRING, &foo); + + dbus_message_iter_close_container (&arr, &str); + } + dbus_message_iter_close_container (&iter, &arr); + + fprintf (stderr, "native struct marshalling ok\n"); + + dbus_message_unref (msg); +} + + +void test_struct_simple () +{ + typedef struct { + char *foo; + char *baa; + char *baz; + } FooBaa; + GArray *a1 = NULL, *a2 = NULL; + DBusMessage *msg; + + a1 = g_array_new (FALSE, FALSE, sizeof (FooBaa)); + g_array_set_size (a1, 2); + g_array_index (a1, FooBaa, 0).foo = "foo"; + g_array_index (a1, FooBaa, 0).baa = "baa"; + g_array_index (a1, FooBaa, 0).baz = "baz"; + g_array_index (a1, FooBaa, 1).foo = "Foo"; + g_array_index (a1, FooBaa, 1).baa = "baA"; + g_array_index (a1, FooBaa, 1).baz = "BaZ"; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + marshal (msg, "a(sss)", &a1); + demarshal (msg, "a(sss)", &a2); + + g_assert (a2 != NULL); + g_assert (a2 != a1); + g_assert (a2->len == 2); + g_assert (!strcmp (g_array_index (a2, FooBaa, 0).foo, "foo")); + g_assert (!strcmp (g_array_index (a2, FooBaa, 0).baa, "baa")); + g_assert (!strcmp (g_array_index (a2, FooBaa, 0).baz, "baz")); + g_assert (!strcmp (g_array_index (a2, FooBaa, 1).foo, "Foo")); + g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baa, "baA")); + g_assert (!strcmp (g_array_index (a2, FooBaa, 1).baz, "BaZ")); + + fprintf (stderr, "simple struct ok\n"); + + dbind_any_free ("a(sss)", &a2); + dbus_message_unref (msg); +} + +void test_struct_complex () +{ + typedef struct { + dbus_int32_t x, y; + } Point; + typedef struct { + unsigned char pad1; + double val; + Point tl, br; + char pad2; + char *name; + } Complex; +#define TYPEOF_POINT \ + DBUS_STRUCT_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_INT32_AS_STRING \ + DBUS_TYPE_INT32_AS_STRING \ + DBUS_STRUCT_END_CHAR_AS_STRING +#define TYPEOF_COMPLEX \ + DBUS_STRUCT_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_DOUBLE_AS_STRING \ + TYPEOF_POINT \ + TYPEOF_POINT \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_TYPE_STRING_AS_STRING \ + DBUS_STRUCT_END_CHAR_AS_STRING + + + DBusMessage *msg; + Complex c1, c2; + + memset (&c1, 0, sizeof (c1)); + memset (&c2, 0, sizeof (c2)); + + c1.pad1 = 2; + c1.val = 0.1327569; + c1.tl.x = 1; + c1.tl.y = 17; + c1.br.x = 2587; + c1.br.y = -1; + c1.pad2 = 1; + c1.name = "stroustrup"; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + marshal (msg, TYPEOF_COMPLEX, &c1); + demarshal (msg, TYPEOF_COMPLEX, &c2); + + g_assert (c2.pad1 == 2); + g_assert (c2.val == c1.val); + g_assert (c2.val != 0); + g_assert (c2.tl.x == 1); + g_assert (c2.tl.y == 17); + g_assert (c2.br.x == 2587); + g_assert (c2.br.y == -1); + g_assert (c2.pad2 == 1); + g_assert (!strcmp (c1.name, "stroustrup")); + + fprintf (stderr, "complex struct ok\n"); + + dbind_any_free (TYPEOF_COMPLEX, &c2); + dbus_message_unref (msg); +} + +void test_struct_with_array () +{ + typedef struct { + GArray *vals; + unsigned char pad1; + } ArrayStruct; +#define TYPEOF_ARRAYSTRUCT \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_STRUCT_BEGIN_CHAR_AS_STRING \ + DBUS_TYPE_ARRAY_AS_STRING \ + DBUS_TYPE_UINT32_AS_STRING \ + DBUS_TYPE_BYTE_AS_STRING \ + DBUS_STRUCT_END_CHAR_AS_STRING + + + DBusMessage *msg; + GArray *a1, *a2; + ArrayStruct *p, *q; + + + a1 = g_array_new (FALSE, FALSE, sizeof (ArrayStruct)); + g_array_set_size (a1, 2); + p = &g_array_index (a1, ArrayStruct, 0); + p[0].vals = g_array_new (FALSE, FALSE, sizeof (dbus_uint32_t)); + g_array_set_size (p[0].vals, 2); + g_array_index (p[0].vals, dbus_uint32_t, 0) = 1; + g_array_index (p[0].vals, dbus_uint32_t, 1) = 1000; + p[0].pad1 = 2; + p[1].vals = g_array_new (FALSE, FALSE, sizeof (dbus_uint32_t)); + g_array_set_size (p[1].vals, 2); + g_array_index (p[1].vals, dbus_uint32_t, 0) = 1000000; + g_array_index (p[1].vals, dbus_uint32_t, 1) = 1000000000; + p[1].pad1 = 8; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + marshal (msg, TYPEOF_ARRAYSTRUCT, &a1); + demarshal (msg, TYPEOF_ARRAYSTRUCT, &a2); + + q = &g_array_index (a2, ArrayStruct, 0); + g_assert (p[0].pad1 == 2); + g_assert (g_array_index (p[1].vals, dbus_uint32_t, 1) == 1000000000); + + fprintf (stderr, "struct with array ok\n"); + + dbind_any_free (TYPEOF_ARRAYSTRUCT, &a2); + dbus_message_unref (msg); + g_array_free (p[0].vals, TRUE); + g_array_free (p[1].vals, TRUE); +} + +void test_twovals () +{ + typedef struct { + dbus_int32_t v1; + dbus_int32_t v2; + } TwoVal; +#define TYPEOF_TWOVAL \ + DBUS_TYPE_INT32_AS_STRING \ + DBUS_TYPE_INT32_AS_STRING \ + + DBusMessage *msg; + DBusMessageIter iter; + TwoVal i, o; + char *type_twoval = TYPEOF_TWOVAL; + char *type; + void *ptr; + + msg = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); + i.v1 = 42; + i.v2 = 1764; + dbus_message_iter_init_append (msg, &iter); + type = type_twoval; + ptr = &i; + dbind_any_marshal (&iter, &type, &ptr); + dbind_any_marshal (&iter, &type, &ptr); + dbus_message_iter_init (msg, &iter); + type = type_twoval; + ptr = &o; + dbind_any_demarshal (&iter, &type, &ptr); + dbind_any_demarshal (&iter, &type, &ptr); + g_assert (o.v1 == 42); + g_assert (o.v2 == 1764); + g_assert (i.v1 == o.v1); + g_assert (i.v2 == o.v2); + + dbind_any_free ("ii", &o); /* nop */ + dbus_message_unref (msg); + + fprintf (stderr, "two-val ok\n"); +} + +void test_marshalling () +{ + test_simple (); + test_array (); + test_struct_native (); + test_struct_simple (); + test_struct_complex (); + test_struct_with_array (); + test_twovals (); + + fprintf (stderr, "Marshalling ok\n"); +} + +void test_teamspaces (DBusConnection *bus) +{ + GArray *spaces; + DBusError error; + int i; + typedef struct { + char *name; + char *id; + char *url; + } TeamSpace; + + dbus_error_init (&error); + if (!dbind_method_call_reentrant (bus, + NULL, + DESKICE_PATH, + DESKICE_NAMESPACE, + "GetTeamList", + &error, + "=>a(sss)", + &spaces)) { + fprintf (stderr, "Error getting team spaces %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return; + } + + if (!spaces) { + fprintf (stderr, "no teamspaces\n"); + return; + } + fprintf (stderr, "%d teamspace(s)\n", spaces->len); + for (i = 0; i < spaces->len; i++) { + TeamSpace *space = &g_array_index (spaces, TeamSpace, i); + fprintf (stderr, "\t%d: %s, %s, %s\n", i, space->name, space->id, space->url); + } + + dbind_any_free_ptr ("a(sss)", spaces); +} + +void test_helpers () +{ + dbind_find_c_alignment ("(sss)"); + dbind_find_c_alignment ("a(sss)"); + dbind_find_c_alignment ("(s(s)yd(d)s)"); + fprintf (stderr, "helpers passed\n"); +} + +int main (int argc, char **argv) +{ + DBusConnection *bus; + DBusError err; + + dbus_error_init (&err); + + bus = dbus_bus_get (DBUS_BUS_SESSION, &err); + + test_helpers (); + test_marshalling (); + test_teamspaces (bus); + + return 0; +} diff --git a/droute/Makefile.am b/droute/Makefile.am new file mode 100644 index 0000000..1c4b8e3 --- /dev/null +++ b/droute/Makefile.am @@ -0,0 +1,28 @@ +noinst_LTLIBRARIES = libdroute.la + +libdroute_la_CFLAGS = $(DBUS_GLIB_CFLAGS) \ + -DATSPI_INTROSPECTION_PATH=\"$(pkgdatadir)/$(DEFAULT_ATSPI_INTROSPECTION_PATH)\"\ + -I$(top_builddir)\ + -I$(top_srcdir) + +libdroute_la_SOURCES =\ + droute.c\ + droute.h\ + droute-variant.c\ + droute-variant.h\ + droute-pairhash.c\ + droute-pairhash.h +libdroute_la_LIBADD = $(DBUS_GLIB_LIBS) + +TESTS = droute-test + +check_PROGRAMS = droute-test +droute_test_SOURCES = droute-test.c +droute_test_CFLAGS = $(DBUS_GLIB_CFLAGS) \ + -I$(top_builddir)\ + -I$(top_srcdir)\ + -DTEST_INTROSPECTION_DIRECTORY=\"$(top_srcdir)/droute\" + +droute_test_LDFLAGS = $(top_builddir)/dbind/libdbind.la\ + libdroute.la\ + $(DBUS_GLIB_LIBS) diff --git a/droute/droute-pairhash.c b/droute/droute-pairhash.c new file mode 100644 index 0000000..f3b8da2 --- /dev/null +++ b/droute/droute-pairhash.c @@ -0,0 +1,87 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Codethink Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "droute-pairhash.h" + +/*---------------------------------------------------------------------------*/ + +static guint +str_hash (guint32 h, const char *p) +{ + for (p += 1; *p != '\0'; p++) + h = (h << 5) - h + *p; + + return h; +} + +/*---------------------------------------------------------------------------*/ + +StrPair * +str_pair_new (const gchar *one, const gchar *two) +{ + StrPair *pair; + + pair = g_new (StrPair, 1); + pair->one = one; + pair->two = two; + return pair; +} + +guint +str_pair_hash (gconstpointer key) +{ + StrPair *pair = (StrPair *) key; + guint hash = 0; + + /*g_return_val_if_fail (pair != NULL, 0); + g_return_val_if_fail (pair->one != NULL, 0); + g_return_val_if_fail (pair->two != NULL, 0); + */ + + if (*(pair->two) != '\0') + { + hash = *(pair->two); + hash = str_hash (hash, ++(pair->two)); + hash = str_hash (hash, pair->one); + } + + return hash; +} + +gboolean +str_pair_equal (gconstpointer a, gconstpointer b) +{ + StrPair *ap = (StrPair *) a; + StrPair *bp = (StrPair *) b; + + if (g_str_equal (ap->one, bp->one) && + g_str_equal (ap->two, bp->two)) + { + return TRUE; + } + else + { + return FALSE; + } +} + +/*END------------------------------------------------------------------------*/ diff --git a/droute/droute-pairhash.h b/droute/droute-pairhash.h new file mode 100644 index 0000000..1491c2d --- /dev/null +++ b/droute/droute-pairhash.h @@ -0,0 +1,41 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Codethink Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _DROUTE_PAIRHASH_H +#define _DROUTE_PAIRHASH_H + +#include + +typedef struct _StrPair StrPair; +struct _StrPair +{ + const gchar *one; + const gchar *two; +}; + +StrPair *str_pair_new (const gchar *one, + const gchar *two); + +guint str_pair_hash (gconstpointer key); +gboolean str_pair_equal (gconstpointer a, + gconstpointer b); + +#endif /* _DROUTE_PAIRHASH_H */ diff --git a/droute/droute-test.c b/droute/droute-test.c new file mode 100644 index 0000000..8b3fb7c --- /dev/null +++ b/droute/droute-test.c @@ -0,0 +1,243 @@ +#include +#include +#include +#include +#include + +#include "dbus/dbus-glib-lowlevel.h" + +#define TEST_OBJECT_PATH "/test/object" +#define TEST_INTERFACE_ONE "test.interface.One" +#define TEST_INTERFACE_TWO "test.interface.Two" + +#define OBJECT_ONE "ObjectOne"; +#define OBJECT_TWO "ObjectTwo"; + +#if !defined TEST_INTROSPECTION_DIRECTORY + #error "No introspection XML directory defined" +#endif + +#define STRING_ONE "StringOne" +#define STRING_TWO "StringTwo" + +#define INT_ONE 0 +#define INT_TWO 456 + +#define NONE_REPLY_STRING "NoneMethod" + +typedef struct _AnObject +{ + gchar *astring; + guint *anint; +} AnObject; + +static DBusConnection *bus; +static GMainLoop *main_loop; +static gboolean success = TRUE; + +static DBusMessage * +impl_null (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + DBusMessage *reply; + + reply = dbus_message_new_method_return (message); + return reply; +} + +static DBusMessage * +impl_getInt (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + AnObject *object = (AnObject *) user_data; + DBusMessage *reply; + DBusError error; + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID); + return reply; +} + +static DBusMessage * +impl_setInt (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + AnObject *object = (AnObject *) user_data; + DBusMessage *reply; + DBusError error; + + dbus_error_init (&error); + + dbus_message_get_args (message, &error, DBUS_TYPE_INT32, &(object->anint), DBUS_TYPE_INVALID); + + reply = dbus_message_new_method_return (message); + return reply; +} + +static DBusMessage * +impl_getString (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + AnObject *object = (AnObject *) user_data; + DBusMessage *reply; + DBusError error; + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID); + return reply; +} + +static DBusMessage * +impl_setString (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + AnObject *object = (AnObject *) user_data; + DBusMessage *reply; + DBusError error; + + dbus_error_init (&error); + + g_free (object->astring); + dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &(object->astring), DBUS_TYPE_INVALID); + + reply = dbus_message_new_method_return (message); + return reply; +} + +static DBusMessage * +impl_getInterfaceOne (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + DBusMessage *reply; + DBusError error; + gchar *itf = TEST_INTERFACE_ONE; + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID); + return reply; +} + +static DBusMessage * +impl_getInterfaceTwo (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + DBusMessage *reply; + DBusError error; + gchar *itf = TEST_INTERFACE_TWO; + + dbus_error_init (&error); + + reply = dbus_message_new_method_return (message); + dbus_message_append_args (reply, DBUS_TYPE_STRING, &itf, DBUS_TYPE_INVALID); + return reply; +} + +static DRouteMethod test_methods_one[] = { + {impl_null, "null"}, + {impl_getInt, "getInt"}, + {impl_setInt, "setInt"}, + {impl_getString, "getString"}, + {impl_setString, "setString"}, + {impl_getInterfaceOne, "getInterfaceOne"}, + {NULL, NULL} +}; + +static DRouteMethod test_methods_two[] = { + {impl_null, "null"}, + {impl_getInt, "getInt"}, + {impl_setInt, "setInt"}, + {impl_getString, "getString"}, + {impl_setString, "setString"}, + {impl_getInterfaceTwo, "getInterfaceTwo"}, + {NULL, NULL} +}; + +static DRouteProperty test_properties[] = { + {NULL, NULL, NULL} +}; + +gboolean +do_tests_func (gpointer data) +{ + DBusError error; + const gchar *bus_name; + + gchar *expected_string; + gchar *result_string; + + dbus_error_init (&error); + bus_name = dbus_bus_get_unique_name (bus); + + /* --------------------------------------------------------*/ + + dbind_method_call_reentrant (bus, + bus_name, + TEST_OBJECT_PATH, + TEST_INTERFACE_ONE, + "null", + NULL, + ""); + + /* --------------------------------------------------------*/ + + expected_string = TEST_INTERFACE_ONE; + result_string = NULL; + dbind_method_call_reentrant (bus, + bus_name, + TEST_OBJECT_PATH, + TEST_INTERFACE_ONE, + "getInterfaceOne", + NULL, + "=>s", + &result_string); + if (g_strcmp0(expected_string, result_string)) + { + g_print ("Failed: reply to getInterfaceOne not as expected\n"); + goto out; + } + + /* --------------------------------------------------------*/ + +out: + g_main_loop_quit (main_loop); + return FALSE; +} + + +int main (int argc, char **argv) +{ + DRouteContext *cnx; + DRoutePath *path; + AnObject *object; + DBusError error; + + /* Setup some server object */ + + object = g_new0(AnObject, 1); + object->astring = g_strdup (STRING_ONE); + object->anint = INT_ONE; + + dbus_error_init (&error); + main_loop = g_main_loop_new(NULL, FALSE); + bus = dbus_bus_get (DBUS_BUS_SESSION, &error); + dbus_connection_setup_with_g_main(bus, g_main_context_default()); + + cnx = droute_new (bus, TEST_INTROSPECTION_DIRECTORY); + path = droute_add_one (cnx, TEST_OBJECT_PATH, object); + + droute_path_add_interface (path, + TEST_INTERFACE_ONE, + test_methods_one, + test_properties); + + droute_path_add_interface (path, + TEST_INTERFACE_TWO, + test_methods_two, + test_properties); + + g_idle_add (do_tests_func, NULL); + g_main_run(main_loop); + if (success) + return 0; + else + return 1; +} diff --git a/droute/droute-variant.c b/droute/droute-variant.c new file mode 100644 index 0000000..d4b5ca6 --- /dev/null +++ b/droute/droute-variant.c @@ -0,0 +1,118 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "droute-variant.h" + +/*---------------------------------------------------------------------------*/ + +dbus_bool_t +droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val) +{ + DBusMessageIter sub; + + if (!dbus_message_iter_open_container + (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &sub)) + { + return FALSE; + } + dbus_message_iter_append_basic (&sub, DBUS_TYPE_INT32, &val); + dbus_message_iter_close_container (iter, &sub); + return TRUE; +} + +dbus_bool_t +droute_return_v_double (DBusMessageIter *iter, double val) +{ + DBusMessageIter sub; + + if (!dbus_message_iter_open_container + (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_DOUBLE_AS_STRING, &sub)) + { + return FALSE; + } + dbus_message_iter_append_basic (&sub, DBUS_TYPE_DOUBLE, &val); + dbus_message_iter_close_container (iter, &sub); + return TRUE; +} + +dbus_bool_t +droute_return_v_string (DBusMessageIter *iter, const char *val) +{ + DBusMessageIter sub; + + if (!val) + val = ""; + if (!dbus_message_iter_open_container + (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &sub)) + { + return FALSE; + } + dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING, &val); + dbus_message_iter_close_container (iter, &sub); + return TRUE; +} + +dbus_bool_t +droute_return_v_object (DBusMessageIter *iter, const char *path) +{ + DBusMessageIter sub; + + if (!dbus_message_iter_open_container + (iter, DBUS_TYPE_VARIANT, DBUS_TYPE_OBJECT_PATH_AS_STRING, &sub)) + { + return FALSE; + } + dbus_message_iter_append_basic (&sub, DBUS_TYPE_OBJECT_PATH, &path); + dbus_message_iter_close_container (iter, &sub); + return TRUE; +} + +/*---------------------------------------------------------------------------*/ + +dbus_int32_t +droute_get_v_int32 (DBusMessageIter *iter) +{ + DBusMessageIter sub; + dbus_int32_t rv; + + // TODO- ensure we have the correct type + dbus_message_iter_recurse (iter, &sub); + dbus_message_iter_get_basic (&sub, &rv); + return rv; +} + +const char * +droute_get_v_string (DBusMessageIter *iter) +{ + DBusMessageIter sub; + char *rv; + + // TODO- ensure we have the correct type + dbus_message_iter_recurse (iter, &sub); + dbus_message_iter_get_basic (&sub, &rv); + return rv; +} + +/*END------------------------------------------------------------------------*/ diff --git a/droute/droute-variant.h b/droute/droute-variant.h new file mode 100644 index 0000000..47feb96 --- /dev/null +++ b/droute/droute-variant.h @@ -0,0 +1,35 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _DROUTE_VARIANT_H +#define _DROUTE_VARIANT_H + +#include + +dbus_bool_t droute_return_v_int32 (DBusMessageIter *iter, dbus_int32_t val); +dbus_bool_t droute_return_v_double (DBusMessageIter *iter, double val); +dbus_bool_t droute_return_v_string (DBusMessageIter *iter, const char *val); +dbus_bool_t droute_return_v_object (DBusMessageIter *iter, const char *path); + +dbus_int32_t droute_get_v_int32 (DBusMessageIter *iter); +const char *droute_get_v_string (DBusMessageIter *iter); + +#endif /* _DROUTE_VARIANT_H */ diff --git a/droute/droute.c b/droute/droute.c new file mode 100644 index 0000000..0cec8be --- /dev/null +++ b/droute/droute.c @@ -0,0 +1,598 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Novell, Inc. + * Copyright 2008 Codethink Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include + +#include "droute.h" +#include "droute-pairhash.h" + +#define CHUNKS_DEFAULT (512) + +#define oom() g_error ("D-Bus out of memory, this message will fail anyway") + +#if defined DROUTE_DEBUG + #define _DROUTE_DEBUG(format, args...) g_print (format , ## args) +#else + #define _DROUTE_DEBUG(format, args...) +#endif + +struct _DRouteContext +{ + DBusConnection *bus; + GPtrArray *registered_paths; + + gchar *introspect_dir; +}; + +struct _DRoutePath +{ + DRouteContext *cnx; + GStringChunk *chunks; + GPtrArray *interfaces; + GHashTable *methods; + GHashTable *properties; + + void *user_data; + DRouteGetDatumFunction get_datum; +}; + +/*---------------------------------------------------------------------------*/ + +typedef struct PropertyPair +{ + DRoutePropertyFunction get; + DRoutePropertyFunction set; +} PropertyPair; + +/*---------------------------------------------------------------------------*/ + +static DBusHandlerResult +handle_message (DBusConnection *bus, DBusMessage *message, void *user_data); + +/*---------------------------------------------------------------------------*/ + +static DRoutePath * +path_new (DRouteContext *cnx, + void *user_data, + DRouteGetDatumFunction get_datum) +{ + DRoutePath *new_path; + + new_path = g_new0 (DRoutePath, 1); + new_path->cnx = cnx; + new_path->chunks = g_string_chunk_new (CHUNKS_DEFAULT); + new_path->interfaces = g_ptr_array_new (); + + new_path->methods = g_hash_table_new_full ((GHashFunc)str_pair_hash, + str_pair_equal, + g_free, + NULL); + + new_path->properties = g_hash_table_new_full ((GHashFunc)str_pair_hash, + str_pair_equal, + g_free, + NULL); + + new_path->user_data = user_data; + new_path->get_datum = get_datum; + + return new_path; +} + +static void +path_free (DRoutePath *path, gpointer user_data) +{ + g_string_chunk_free (path->chunks); + g_ptr_array_free (path->interfaces, TRUE); + g_hash_table_destroy (path->methods); + g_hash_table_destroy (path->properties); +} + +static void * +path_get_datum (DRoutePath *path, const gchar *pathstr) +{ + if (path->get_datum != NULL) + return (path->get_datum) (pathstr, path->user_data); + else + return path->user_data; +} + +/*---------------------------------------------------------------------------*/ + +DRouteContext * +droute_new (DBusConnection *bus, const char *introspect_dir) +{ + DRouteContext *cnx; + + cnx = g_new0 (DRouteContext, 1); + cnx->bus = bus; + cnx->registered_paths = g_ptr_array_new (); + cnx->introspect_dir = g_strdup(introspect_dir); + + return cnx; +} + +void +droute_free (DRouteContext *cnx) +{ + g_ptr_array_foreach (cnx->registered_paths, (GFunc) path_free, NULL); + g_free (cnx->introspect_dir); + g_free (cnx); +} + +/*---------------------------------------------------------------------------*/ + +DBusConnection * +droute_get_bus (DRouteContext *cnx) +{ + return cnx->bus; +} + +/*---------------------------------------------------------------------------*/ + +static DBusObjectPathVTable droute_vtable = +{ + NULL, + &handle_message, + NULL, NULL, NULL, NULL +}; + +DRoutePath * +droute_add_one (DRouteContext *cnx, + const char *path, + const void *data) +{ + DRoutePath *new_path; + gboolean registered; + + new_path = path_new (cnx, (void *) data, NULL); + + registered = dbus_connection_register_object_path (cnx->bus, path, &droute_vtable, new_path); + if (!registered) + oom(); + + g_ptr_array_add (cnx->registered_paths, new_path); + return new_path; +} + +DRoutePath * +droute_add_many (DRouteContext *cnx, + const char *path, + const void *data, + const DRouteGetDatumFunction get_datum) +{ + DRoutePath *new_path; + + new_path = path_new (cnx, (void *) data, get_datum); + + if (!dbus_connection_register_fallback (cnx->bus, path, &droute_vtable, new_path)) + oom(); + + g_ptr_array_add (cnx->registered_paths, new_path); + return new_path; +} + +/*---------------------------------------------------------------------------*/ + +void +droute_path_add_interface(DRoutePath *path, + const char *name, + const DRouteMethod *methods, + const DRouteProperty *properties) +{ + gchar *itf; + + g_return_if_fail (name != NULL); + + itf = g_string_chunk_insert (path->chunks, name); + g_ptr_array_add (path->interfaces, itf); + + for (; methods != NULL && methods->name != NULL; methods++) + { + gchar *meth; + + meth = g_string_chunk_insert (path->chunks, methods->name); + g_hash_table_insert (path->methods, str_pair_new (itf, meth), methods->func); + } + + for (; properties != NULL && properties->name != NULL; properties++) + { + gchar *prop; + PropertyPair *pair; + + prop = g_string_chunk_insert (path->chunks, properties->name); + pair = g_new (PropertyPair, 1); + pair->get = properties->get; + pair->set = properties->set; + g_hash_table_insert (path->properties, str_pair_new (itf, prop), pair); + } +} + +/*---------------------------------------------------------------------------*/ + +/* The data structures don't support an efficient implementation of GetAll + * and I don't really care. + */ +static DBusMessage * +impl_prop_GetAll (DBusMessage *message, + DRoutePath *path, + const char *pathstr) +{ + DBusMessageIter iter, iter_dict, iter_dict_entry; + DBusMessage *reply; + DBusError error; + GHashTableIter prop_iter; + + StrPair *key; + PropertyPair *value; + gchar *iface; + + void *datum = path_get_datum (path, pathstr); + + dbus_error_init (&error); + if (!dbus_message_get_args + (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID)) + return dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message); + + reply = dbus_message_new_method_return (message); + if (!reply) + oom (); + + dbus_message_iter_init_append (reply, &iter); + if (!dbus_message_iter_open_container + (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict)) + oom (); + + g_hash_table_iter_init (&prop_iter, path->properties); + while (g_hash_table_iter_next (&prop_iter, (gpointer*)&key, (gpointer*)&value)) + { + if (!g_strcmp0 (key->one, iface)) + { + if (!value->get) + continue; + if (!dbus_message_iter_open_container + (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry)) + oom (); + dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, + key->two); + (value->get) (&iter_dict_entry, datum); + if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry)) + oom (); + } + } + + if (!dbus_message_iter_close_container (&iter, &iter_dict)) + oom (); + return reply; +} + +static DBusMessage * +impl_prop_GetSet (DBusMessage *message, + DRoutePath *path, + const char *pathstr, + gboolean get) +{ + DBusMessage *reply = NULL; + DBusError error; + + StrPair pair; + PropertyPair *prop_funcs = NULL; + + + dbus_error_init (&error); + if (!dbus_message_get_args (message, + &error, + DBUS_TYPE_STRING, + &(pair.one), + DBUS_TYPE_STRING, + &(pair.two), + DBUS_TYPE_INVALID)) + return dbus_message_new_error (message, DBUS_ERROR_FAILED, error.message); + + _DROUTE_DEBUG ("DRoute (handle prop): %s|%s on %s\n", pair.one, pair.two, pathstr); + + prop_funcs = (PropertyPair *) g_hash_table_lookup (path->properties, &pair); + if (!prop_funcs) + return dbus_message_new_error (message, DBUS_ERROR_FAILED, "Property unavailable"); + + if (get && prop_funcs->get) + { + void *datum = path_get_datum (path, pathstr); + DBusMessageIter iter; + + _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr); + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + if (!(prop_funcs->get) (&iter, datum)) + { + dbus_message_unref (reply); + reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Get failed"); + } + } + else if (!get && prop_funcs->set) + { + void *datum = path_get_datum (path, pathstr); + DBusMessageIter iter; + + _DROUTE_DEBUG ("DRoute (handle prop Get): %s|%s on %s\n", pair.one, pair.two, pathstr); + + dbus_message_iter_init (message, &iter); + /* Skip the interface and property name */ + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + (prop_funcs->set) (&iter, datum); + + reply = dbus_message_new_method_return (message); + } + else + { + reply = dbus_message_new_error (message, DBUS_ERROR_FAILED, "Getter or setter unavailable"); + } + + return reply; +} + +static DBusHandlerResult +handle_properties (DBusConnection *bus, + DBusMessage *message, + DRoutePath *path, + const gchar *iface, + const gchar *member, + const gchar *pathstr) +{ + DBusMessage *reply; + DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED; + + if (!g_strcmp0(member, "GetAll")) + reply = impl_prop_GetAll (message, path, pathstr); + else if (!g_strcmp0 (member, "Get")) + reply = impl_prop_GetSet (message, path, pathstr, TRUE); + else if (!g_strcmp0 (member, "Set")) + reply = impl_prop_GetSet (message, path, pathstr, FALSE); + else + result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (reply) + { + dbus_connection_send (bus, reply, NULL); + dbus_message_unref (reply); + } + + return result; +} + +/*---------------------------------------------------------------------------*/ + +static const char *introspection_header = +"\n"; + +static const char *introspection_node_element = +"\n"; + +static const char *introspection_footer = +""; + +static void +append_interface (GString *str, + const gchar *interface, + const gchar *directory) +{ + gchar *filename; + gchar *contents; + gsize len; + + GError *err = NULL; + + filename = g_build_filename (directory, interface, NULL); + + if (g_file_get_contents (filename, &contents, &len, &err)) + { + g_string_append_len (str, contents, len); + } + else + { + g_warning ("AT-SPI: Cannot find introspection XML file %s - %s", + filename, err->message); + g_error_free (err); + } + + g_string_append (str, "\n"); + g_free (filename); + g_free (contents); +} + +static DBusHandlerResult +handle_introspection (DBusConnection *bus, + DBusMessage *message, + DRoutePath *path, + const gchar *iface, + const gchar *member, + const gchar *pathstr) +{ + GString *output; + gchar *final; + gint i; + + DBusMessage *reply; + + _DROUTE_DEBUG ("DRoute (handle introspection): %s\n", pathstr); + + if (g_strcmp0 (member, "Introspect")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + output = g_string_new(introspection_header); + + g_string_append_printf(output, introspection_node_element, pathstr); + + for (i=0; i < path->interfaces->len; i++) + { + gchar *interface = (gchar *) g_ptr_array_index (path->interfaces, i); + append_interface(output, interface, path->cnx->introspect_dir); + } + + g_string_append(output, introspection_footer); + final = g_string_free(output, FALSE); + + reply = dbus_message_new_method_return (message); + if (!reply) + oom (); + dbus_message_append_args(reply, DBUS_TYPE_STRING, &final, + DBUS_TYPE_INVALID); + dbus_connection_send (bus, reply, NULL); + + dbus_message_unref (reply); + g_free(final); + return DBUS_HANDLER_RESULT_HANDLED; +} + +/*---------------------------------------------------------------------------*/ + +static DBusHandlerResult +handle_other (DBusConnection *bus, + DBusMessage *message, + DRoutePath *path, + const gchar *iface, + const gchar *member, + const gchar *pathstr) +{ + gint result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + StrPair pair; + DRouteFunction func; + DBusMessage *reply = NULL; + + pair.one = iface; + pair.two = member; + + _DROUTE_DEBUG ("DRoute (handle other): %s|%s on %s\n", member, iface, pathstr); + + func = (DRouteFunction) g_hash_table_lookup (path->methods, &pair); + if (func != NULL) + { + void *datum = path_get_datum (path, pathstr); + + reply = (func) (bus, message, datum); + + if (!reply) + { + /* All D-Bus method calls must have a reply. + * If one is not provided presume that the call has a void + * return and no error has occured. + */ + reply = dbus_message_new_method_return (message); + } + dbus_connection_send (bus, reply, NULL); + dbus_message_unref (reply); + result = DBUS_HANDLER_RESULT_HANDLED; + } + + _DROUTE_DEBUG ("DRoute (handle other) (reply): type %d\n", + dbus_message_get_type(reply)); + return result; +} + +/*---------------------------------------------------------------------------*/ + +static DBusHandlerResult +handle_message (DBusConnection *bus, DBusMessage *message, void *user_data) +{ + DRoutePath *path = (DRoutePath *) user_data; + const gchar *iface = dbus_message_get_interface (message); + const gchar *member = dbus_message_get_member (message); + const gint type = dbus_message_get_type (message); + const gchar *pathstr = dbus_message_get_path (message); + + /* Check for basic reasons not to handle */ + if (type != DBUS_MESSAGE_TYPE_METHOD_CALL || + member == NULL || + iface == NULL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!strcmp (iface, "org.freedesktop.DBus.Properties")) + return handle_properties (bus, message, path, iface, member, pathstr); + + if (!strcmp (iface, "org.freedesktop.DBus.Introspectable")) + return handle_introspection (bus, message, path, iface, member, pathstr); + + return handle_other (bus, message, path, iface, member, pathstr); +} + +/*---------------------------------------------------------------------------*/ + +DBusMessage * +droute_not_yet_handled_error (DBusMessage *message) +{ + DBusMessage *reply; + gchar *errmsg; + + errmsg= g_strdup_printf ( + "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist\n", + dbus_message_get_member (message), + dbus_message_get_signature (message), + dbus_message_get_interface (message)); + reply = dbus_message_new_error (message, + DBUS_ERROR_UNKNOWN_METHOD, + errmsg); + g_free (errmsg); + return reply; +} + +DBusMessage * +droute_out_of_memory_error (DBusMessage *message) +{ + DBusMessage *reply; + gchar *errmsg; + + errmsg= g_strdup_printf ( + "Method \"%s\" with signature \"%s\" on interface \"%s\" could not be processed due to lack of memory\n", + dbus_message_get_member (message), + dbus_message_get_signature (message), + dbus_message_get_interface (message)); + reply = dbus_message_new_error (message, + DBUS_ERROR_NO_MEMORY, + errmsg); + g_free (errmsg); + return reply; +} + +DBusMessage * +droute_invalid_arguments_error (DBusMessage *message) +{ + DBusMessage *reply; + gchar *errmsg; + + errmsg= g_strdup_printf ( + "Method \"%s\" with signature \"%s\" on interface \"%s\" was supplied with invalid arguments\n", + dbus_message_get_member (message), + dbus_message_get_signature (message), + dbus_message_get_interface (message)); + reply = dbus_message_new_error (message, + DBUS_ERROR_INVALID_ARGS, + errmsg); + g_free (errmsg); + return reply; +} + +/*END------------------------------------------------------------------------*/ diff --git a/droute/droute.h b/droute/droute.h new file mode 100644 index 0000000..a892c62 --- /dev/null +++ b/droute/droute.h @@ -0,0 +1,95 @@ +/* + * AT-SPI - Assistive Technology Service Provider Interface + * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap) + * + * Copyright 2008 Novell, Inc. + * Copyright 2008 Codethink Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef _DROUTE_H +#define _DROUTE_H + +#include +#include + +#include + + +typedef DBusMessage *(*DRouteFunction) (DBusConnection *, DBusMessage *, void *); +typedef dbus_bool_t (*DRoutePropertyFunction) (DBusMessageIter *, void *); + +typedef void *(*DRouteGetDatumFunction) (const char *, void *); + +typedef struct _DRouteMethod DRouteMethod; +struct _DRouteMethod +{ + DRouteFunction func; + const char *name; +}; + +typedef struct _DRouteProperty DRouteProperty; +struct _DRouteProperty +{ + DRoutePropertyFunction get; + DRoutePropertyFunction set; + const char *name; +}; + +/*---------------------------------------------------------------------------*/ + +typedef struct _DRouteContext DRouteContext; + +typedef struct _DRoutePath DRoutePath; + +/*---------------------------------------------------------------------------*/ + +DRouteContext * +droute_new (DBusConnection *bus, + const char *introspect_dir); +void +droute_free (DRouteContext *cnx); + +DRoutePath * +droute_add_one (DRouteContext *cnx, + const char *path, + const void *data); + +DRoutePath * +droute_add_many (DRouteContext *cnx, + const char *path, + const void *data, + const DRouteGetDatumFunction get_datum); + +void +droute_path_add_interface (DRoutePath *path, + const char *name, + const DRouteMethod *methods, + const DRouteProperty *properties); + +DBusMessage * +droute_not_yet_handled_error (DBusMessage *message); + +DBusMessage * +droute_invalid_arguments_error (DBusMessage *message); + +DBusMessage * +droute_out_of_memory_error (DBusMessage *message); + +DBusConnection * +droute_get_bus (DRouteContext *cnx); + +#endif /* _DROUTE_H */ diff --git a/droute/test.interface.One b/droute/test.interface.One new file mode 100644 index 0000000..a8e2206 --- /dev/null +++ b/droute/test.interface.One @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/droute/test.interface.Two b/droute/test.interface.Two new file mode 100644 index 0000000..ca661ec --- /dev/null +++ b/droute/test.interface.Two @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + -- 2.7.4