From b37f0b74994912dea13f33d63d3f1395554944b2 Mon Sep 17 00:00:00 2001 From: Mark Doffman Date: Sun, 7 Dec 2008 23:13:13 +0000 Subject: [PATCH] 2008-12-07 Mark Doffman * dbind/* droute/* Complete refactoring droute to add api for creating single objects and object classes. Minor refactor of dbind, adding interface for marshalling signals. --- dbind/Makefile.am | 4 +- dbind/dbind-any.c | 438 ++++++++------ dbind/dbind-any.h | 15 +- dbind/dbind.c | 321 ++++------ dbind/dbind.h | 48 +- dbind/dbtest.c | 28 +- droute/Makefile.am | 25 +- droute/droute-pairhash.c | 81 +++ droute/{introspect-loader.h => droute-pairhash.h} | 24 +- droute/droute-variant.c | 118 ++++ droute/droute-variant.h | 35 ++ droute/droute.c | 682 +++++++++++++--------- droute/droute.h | 78 +-- droute/introspect-loader.c | 79 --- 14 files changed, 1160 insertions(+), 816 deletions(-) create mode 100644 droute/droute-pairhash.c rename droute/{introspect-loader.h => droute-pairhash.h} (69%) create mode 100644 droute/droute-variant.c create mode 100644 droute/droute-variant.h delete mode 100644 droute/introspect-loader.c diff --git a/dbind/Makefile.am b/dbind/Makefile.am index 97365b8..cc2849e 100644 --- a/dbind/Makefile.am +++ b/dbind/Makefile.am @@ -1,6 +1,6 @@ lib_LTLIBRARIES = libdbind.la -INCLUDES = \ +AM_CPPFLAGS = \ -DG_LOG_DOMAIN=\"dbind\" \ -I$(top_srcdir) \ $(WARN_CFLAGS) \ @@ -21,4 +21,4 @@ TESTS = dbtest check_PROGRAMS = dbtest dbtest_SOURCES = dbtest.c -dbtest_LDFLAGS = libdbind.la \ No newline at end of file +dbtest_LDFLAGS = libdbind.la diff --git a/dbind/dbind-any.c b/dbind/dbind-any.c index 1f784e5..83a87ba 100644 --- a/dbind/dbind-any.c +++ b/dbind/dbind-any.c @@ -1,9 +1,9 @@ /* type driven marshalling */ -#include "config.h" -#include "dbind-config.h" -#define DBUS_API_SUBJECT_TO_CHANGE #include #include + +#include "config.h" +#include "dbind-config.h" #include "dbind-any.h" #undef DEBUG @@ -24,10 +24,20 @@ ((gpointer)ALIGN_VALUE(this, boundary)) #define PTR_PLUS(ptr, offset) \ - ((gpointer) (((guchar *)(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 -unsigned int dbind_find_c_alignment_r (char **type); -unsigned int dbind_find_c_alignment (char *type); +/*---------------------------------------------------------------------------*/ static void warn_braces () @@ -36,26 +46,87 @@ warn_braces () " 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 */ -size_t dbind_gather_alloc_info_r (char **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) { + 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: @@ -78,106 +149,114 @@ size_t dbind_gather_alloc_info_r (char **type) case DBUS_TYPE_ARRAY: return sizeof (void *); case DBUS_STRUCT_BEGIN_CHAR: { - int sum = 0, stralign; + 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, dbind_find_c_alignment (*type)); + sum += dbind_gather_alloc_info_r (type); } - sum = ALIGN_VALUE (sum, stralign); + sum = ALIGN_VALUE (sum, stralign); g_assert (**type == DBUS_STRUCT_END_CHAR); (*type)++; - return sum; + return sum; } case DBUS_TYPE_STRUCT: case DBUS_TYPE_DICT_ENTRY: warn_braces (); - default: - return 0; - } + default: + return 0; + } } -size_t dbind_gather_alloc_info (char *type) +static size_t +dbind_gather_alloc_info (char *type) { return dbind_gather_alloc_info_r (&type); } -unsigned int -dbind_find_c_alignment_r (char **type) -{ - unsigned int retval = 1; +/*---------------------------------------------------------------------------*/ - char t = **type; - (*type)++; +static void +dbind_any_free_r (char **type, void **data) +{ + size_t len; #ifdef DEBUG - fprintf (stderr, "\tfind align for %c (0x%x)\n", t, t); + fprintf (stderr, "any free '%c' to %p\n", **type, *data); #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 */ + 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: - 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); +#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, *child_type_string; + + (*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) { - int elem_align = dbind_find_c_alignment_r (type); - retval = MAX (retval, elem_align); + 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)++; - return retval; + + break; + } 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; - } + } } -unsigned int -dbind_find_c_alignment (char *type) -{ - return dbind_find_c_alignment_r (&type); -} - -#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 +/*---------------------------------------------------------------------------*/ void dbind_any_marshal (DBusMessageIter *iter, @@ -215,7 +294,7 @@ dbind_any_marshal (DBusMessageIter *iter, /* 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); */ + /* 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++) { @@ -230,8 +309,8 @@ dbind_any_marshal (DBusMessageIter *iter, break; } case DBUS_STRUCT_BEGIN_CHAR: { - gconstpointer data0 = *data; - int offset = 0, stralign; + gconstpointer data0 = *data; + int offset = 0, stralign; DBusMessageIter sub; stralign = dbind_find_c_alignment (*type); @@ -243,14 +322,14 @@ dbind_any_marshal (DBusMessageIter *iter, 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); + 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); + offset = ALIGN_VALUE (offset, stralign); + *data = PTR_PLUS (data0, offset); dbus_message_iter_close_container (iter, &sub); @@ -266,6 +345,73 @@ dbind_any_marshal (DBusMessageIter *iter, } } +/*---------------------------------------------------------------------------*/ + +void +dbind_any_marshal_va (DBusMessageIter *iter, + char **arg_types, + va_list args) +{ + char *p = *arg_types; + { + /* 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, @@ -305,13 +451,13 @@ dbind_any_demarshal (DBusMessageIter *iter, (*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) { @@ -326,8 +472,8 @@ dbind_any_demarshal (DBusMessageIter *iter, break; } case DBUS_STRUCT_BEGIN_CHAR: { - gconstpointer data0 = *data; - int offset = 0, stralign; + gconstpointer data0 = *data; + int offset = 0, stralign; DBusMessageIter child; stralign = dbind_find_c_alignment (*type); @@ -338,14 +484,14 @@ dbind_any_demarshal (DBusMessageIter *iter, while (**type != DBUS_STRUCT_END_CHAR) { char *subt = *type; - offset = ALIGN_VALUE (offset, dbind_find_c_alignment (*type)); - *data = PTR_PLUS (data0, offset); + 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); + offset = ALIGN_VALUE (offset, stralign); + *data = PTR_PLUS (data0, offset); g_assert (**type == DBUS_STRUCT_END_CHAR); (*type)++; @@ -360,82 +506,22 @@ dbind_any_demarshal (DBusMessageIter *iter, dbus_message_iter_next (iter); } -static void -dbind_any_free_r (char **type, void **data) -{ - size_t len; - -#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, *child_type_string; - - (*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_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, @@ -450,3 +536,13 @@ 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 index ce6482e..975b244 100644 --- a/dbind/dbind-any.h +++ b/dbind/dbind-any.h @@ -1,17 +1,30 @@ #ifndef _DBIND_ANY_H_ #define _DBIND_ANY_H_ +#define DBUS_API_SUBJECT_TO_CHANGE #include -size_t dbind_gather_alloc_info (char *type); +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); diff --git a/dbind/dbind.c b/dbind/dbind.c index 1bbf0b0..f34bcc4 100644 --- a/dbind/dbind.c +++ b/dbind/dbind.c @@ -1,143 +1,80 @@ -#include "config.h" + + #include -#define DBUS_API_SUBJECT_TO_CHANGE -#include -#include -#include #include +#include + +#include "config.h" +#include "dbind/dbind.h" /* * FIXME: compare types - to ensure they match & * do dynamic padding of structures etc. */ -struct _DBindContext { - DBusConnection *cnx; -}; - -DBindContext * -dbind_create_context (DBusBusType type, DBusError *opt_error) -{ - DBindContext *ctx = NULL; - DBusConnection *cnx; - DBusError *err, real_err; - - if (opt_error) - err = opt_error; - else { - dbus_error_init (&real_err); - err = &real_err; - } - - cnx = dbus_bus_get (DBUS_BUS_SESSION, err); - if (!cnx) - goto out; - - ctx = g_new0 (DBindContext, 1); - ctx->cnx = cnx; - -out: - if (err == &real_err) - dbus_error_free (err); - - return ctx; -} - -void -dbind_context_free (DBindContext *ctx) -{ - if (!ctx) - return; - dbus_connection_unref (ctx->cnx); - g_free (ctx); -} - -dbus_bool_t -dbind_context_method_call (DBindContext *ctx, - const char *bus_name, - const char *path, - const char *interface, - const char *method, - DBusError *opt_error, - const char *arg_types, - ...) -{ - dbus_bool_t success; - va_list args; - - va_start (args, arg_types); - - success = dbind_connection_method_call_va - (ctx->cnx, bus_name, path, interface, method, opt_error, arg_types, args); - - va_end (args); - - return success; -} - -dbus_bool_t -dbind_connection_method_call (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; - va_list args; - - va_start (args, arg_types); - - success = dbind_connection_method_call_va - (cnx, bus_name, path, interface, method, opt_error, arg_types, args); +/*---------------------------------------------------------------------------*/ - va_end (args); - - return success; -} - -static void set_reply (DBusPendingCall *pending, void *user_data) +static void +set_reply (DBusPendingCall *pending, void *user_data) { - void **replyptr = (void **)user_data; + void **replyptr = (void **)user_data; - *replyptr = dbus_pending_call_steal_reply (pending); + *replyptr = dbus_pending_call_steal_reply (pending); } static DBusMessage * -send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout, DBusError *error) +send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error) { - DBusPendingCall *pending; - DBusMessage *reply = NULL; - - if (!dbus_connection_send_with_reply (bus, message, &pending, timeout)) - { - return NULL; - } - dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL); - while (!reply) - { - if (!dbus_connection_read_write_dispatch (bus, timeout)) return NULL; - } - return reply; + 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; } +/** + * 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_connection_method_call_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) +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; DBusMessage *msg = NULL, *reply = NULL; + DBusMessageIter iter; DBusError *err, real_err; char *p; - char *dest; + va_list args; + + va_start (args, arg_types); if (opt_error) err = opt_error; @@ -149,88 +86,17 @@ dbind_connection_method_call_va (DBusConnection *cnx, msg = dbus_message_new_method_call (bus_name, path, interface, method); if (!msg) goto out; - dbus_message_set_auto_start (msg, TRUE); - /* marshal */ - p = (char *)arg_types; - { - DBusMessageIter iter; - - dbus_message_iter_init_append (msg, &iter); - /* 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); - } - } + dbus_message_iter_init (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); - dest = dbus_message_get_destination(msg); - if (!dest) - goto out; - if (!strcmp (dbus_bus_get_unique_name(cnx), dest)) - { - /* Can't use dbus_message_send_with_reply_and_block because it will - * not pass messages on to the provider side, causing deadlock */ - reply = send_and_allow_reentry (cnx, msg, -1, err); - } - else - { - reply = dbus_connection_send_with_reply_and_block (cnx, msg, -1, err); - } + reply = send_and_allow_reentry (cnx, msg, err); if (!reply) goto out; if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) { - char *name = dbus_message_get_error_name (reply); + const char *name = dbus_message_get_error_name (reply); dbus_set_error (err, name, g_strdup ("")); goto out; } @@ -240,14 +106,13 @@ dbind_connection_method_call_va (DBusConnection *cnx, DBusMessageIter iter; p += 2; dbus_message_iter_init (reply, &iter); - for (;*p != '\0';) { - void *arg = va_arg (args, void *); - dbind_any_demarshal (&iter, &p, &arg); - } + dbind_any_demarshal_va (&iter, &p, args); } success = TRUE; out: + va_end (args); + if (msg) dbus_message_unref (msg); @@ -260,3 +125,67 @@ out: 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; + DBusMessage *msg = NULL; + DBusMessageIter iter; + DBusError *err, real_err; + char *p; + va_list args; + + va_start (args, arg_types); + + 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; + + dbus_message_iter_init (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); + + if (!dbus_connection_send (cnx, msg, NULL)) + goto out; + + success = TRUE; +out: + va_end (args); + + if (msg) + dbus_message_unref (msg); + + if (err == &real_err) + dbus_error_free (err); + + return success; +} + +/*END------------------------------------------------------------------------*/ diff --git a/dbind/dbind.h b/dbind/dbind.h index 4e66359..0f6cec8 100644 --- a/dbind/dbind.h +++ b/dbind/dbind.h @@ -1,39 +1,27 @@ #ifndef _DBIND_H_ #define _DBIND_H_ - #define DBUS_API_SUBJECT_TO_CHANGE #include +#include -typedef struct _DBindContext DBindContext; - -DBindContext *dbind_create_context (DBusBusType type, DBusError *opt_error); -void dbind_context_free (DBindContext *ctx); -dbus_bool_t dbind_context_method_call (DBindContext *ctx, - const char *bus_name, - const char *path, - const char *interface, - const char *method, - DBusError *opt_error, - const char *arg_types, - ...); +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 connection variants */ -dbus_bool_t dbind_connection_method_call (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_connection_method_call_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_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 index 9a3ae86..8203c27 100644 --- a/dbind/dbtest.c +++ b/dbind/dbtest.c @@ -1,9 +1,7 @@ #include #include #include -#define DBUS_API_SUBJECT_TO_CHANGE #include -#include /* Wow! dbus is unpleasant to use */ @@ -341,7 +339,7 @@ void test_marshalling () fprintf (stderr, "Marshalling ok\n"); } -void test_teamspaces (DBindContext *ctx) +void test_teamspaces (DBusConnection *bus) { GArray *spaces; DBusError error; @@ -353,9 +351,14 @@ void test_teamspaces (DBindContext *ctx) } TeamSpace; dbus_error_init (&error); - if (!dbind_context_method_call (ctx, NULL, DESKICE_PATH, DESKICE_NAMESPACE, - "GetTeamList", &error, - "=>a(sss)", &spaces)) { + 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); @@ -375,8 +378,6 @@ void test_teamspaces (DBindContext *ctx) dbind_any_free_ptr ("a(sss)", spaces); } -extern dbind_find_c_alignment (char *type); - void test_helpers () { dbind_find_c_alignment ("(sss)"); @@ -387,17 +388,14 @@ void test_helpers () int main (int argc, char **argv) { - DBindContext *ctx; + DBusConnection *bus; + DBusError err; - ctx = dbind_create_context (DBUS_BUS_SESSION, NULL); - if (!ctx) - return 1; + bus = dbus_bus_get (DBUS_BUS_SESSION, &err); test_helpers (); test_marshalling (); - test_teamspaces (ctx); - - dbind_context_free (ctx); + test_teamspaces (bus); return 0; } diff --git a/droute/Makefile.am b/droute/Makefile.am index 2071b8f..46207e4 100644 --- a/droute/Makefile.am +++ b/droute/Makefile.am @@ -1,12 +1,19 @@ noinst_LTLIBRARIES = libdroute.la -libdroute_la_CFLAGS = $(DBUS_GLIB_CFLAGS) $(ATK_CFLAGS)\ - -DATSPI_INTROSPECTION_PATH=\"$(pkgdatadir)/$(DEFAULT_ATSPI_INTROSPECTION_PATH)\"\ - -I$(top_builddir)\ - -I$(top_srcdir) +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 \ - introspect-loader.c \ - introspect-loader.h +libdrouteinclude_HEADERS = \ + droute.h + droute-variant.h +libdrouteincludedir=$(includedir)/dbind-0.1 + +libdroute_la_SOURCES =\ + droute.c\ + droute.h\ + droute-variant.c\ + droute-variant.h\ + droute-pairhash.c\ + droute-pairhash.h diff --git a/droute/droute-pairhash.c b/droute/droute-pairhash.c new file mode 100644 index 0000000..20ff491 --- /dev/null +++ b/droute/droute-pairhash.c @@ -0,0 +1,81 @@ +/* + * 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 signed 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; +} + +gint +str_pair_hash (gconstpointer key) +{ + StrPair *pair = (StrPair *) key; + guint hash = 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/introspect-loader.h b/droute/droute-pairhash.h similarity index 69% rename from droute/introspect-loader.h rename to droute/droute-pairhash.h index bfea0b7..50d4b34 100644 --- a/droute/introspect-loader.h +++ b/droute/droute-pairhash.h @@ -19,19 +19,23 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ - -#ifndef SPI_INTROSPECT_LOADER_H_ -#define SPI_INTROSPECT_LOADER_H_ +#ifndef _DROUTE_PAIRHASH_H +#define _DROUTE_PAIRHASH_H #include -extern const char *spi_introspection_header; - -extern const char *spi_introspection_node_element; +typedef struct _StrPair StrPair; +struct _StrPair +{ + const gchar *one; + const gchar *two; +}; -extern const char *spi_introspection_footer; +StrPair *str_pair_new (const gchar *one, + const gchar *two); -void -spi_append_interface (GString *str, const char *interface); +gint str_pair_hash (gconstpointer key); +gboolean str_pair_equal (gconstpointer a, + gconstpointer b); -#endif /* SPI_INTROSPECT_LOADER_H_ */ +#endif /* _DROUTE_PAIRHASH_H */ 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 index e4c1f91..5b1d9de 100644 --- a/droute/droute.c +++ b/droute/droute.c @@ -3,6 +3,7 @@ * (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 @@ -24,311 +25,464 @@ #include #include "droute.h" +#include "droute-pairhash.h" -static DRouteInterface * -find_iface (DRouteData * data, const char *name) +#define CHUNKS_DEFAULT (512) + +#define oom() g_error ("D-Bus out of memory, this message will fail anyway") + +struct _DRouteContext { - GSList *l; + DBusConnection *bus; + GPtrArray *registered_paths; - for (l = data->interfaces; l; l = g_slist_next (l)) - { - DRouteInterface *iface = (DRouteInterface *) l->data; - if (iface && iface->name && !strcmp (iface->name, name)) - return iface; - } - return NULL; -} + 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 -prop_get_all (DBusConnection * bus, DBusMessage * message, DRouteData * data) +handle_message (DBusConnection *bus, DBusMessage *message, void *user_data); + +/*---------------------------------------------------------------------------*/ + +static DRoutePath * +path_new (DRouteContext *cnx, + void *user_data, + DRouteGetDatumFunction get_datum) { - DRouteInterface *iface_def; - DRouteProperty *prop; - DBusError error; - const char *iface; - const char *path = dbus_message_get_path (message); - DBusMessage *reply; - DBusMessageIter iter, iter_dict, iter_dict_entry; - - dbus_error_init (&error); - if (!dbus_message_get_args - (message, &error, DBUS_TYPE_STRING, &iface, DBUS_TYPE_INVALID)) - { - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - reply = dbus_message_new_method_return (message); - /* tbd: replace tbd with todo? */ - if (!reply) - goto oom; - dbus_message_iter_init_append (reply, &iter); - if (!dbus_message_iter_open_container - (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_dict)) - goto oom; - iface_def = find_iface (data, iface); - if (!iface_def) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (iface_def->properties) - for (prop = iface_def->properties; prop->name; prop++) - { - if (!prop->get) - continue; - if (!dbus_message_iter_open_container - (&iter_dict, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry)) - goto oom; - dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, - &prop->name); - (*prop->get) (path, &iter_dict_entry, data->user_data); - if (!dbus_message_iter_close_container (&iter_dict, &iter_dict_entry)) - goto oom; - } - if (!dbus_message_iter_close_container (&iter, &iter_dict)) - goto oom; - dbus_connection_send (bus, reply, NULL); - dbus_message_unref (reply); - return DBUS_HANDLER_RESULT_HANDLED; -oom: - /* tbd: return a standard out-of-memory error */ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + DRoutePath *new_path; + + new_path = g_new0 (DRoutePath, 0); + 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 DBusHandlerResult -prop (DBusConnection * bus, DBusMessage * message, DRouteData * data) +static void +path_free (DRoutePath *path, gpointer user_data) { - const char *mode = dbus_message_get_member (message); - const char *iface, *member; - const char *path = dbus_message_get_path (message); - int set; - DBusMessage *reply; - DBusMessageIter iter; - DRouteInterface *iface_def; - DRouteProperty *prop = NULL; - - if (!strcmp (mode, "Set")) - set = 1; - else if (!strcmp (mode, "Get")) - set = 0; - else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - reply = dbus_message_new_method_return (message); - dbus_message_iter_init (message, &iter); - dbus_message_iter_get_basic (&iter, &iface); - dbus_message_iter_next (&iter); - dbus_message_iter_get_basic (&iter, &member); - if (!set) - dbus_message_iter_init_append (reply, &iter); - iface_def = find_iface (data, iface); - if (!iface_def) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (iface_def->properties) - for (prop = iface_def->properties; - prop->name && strcmp (prop->name, member); prop++) - if (!prop || !prop->name) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (set) - { - if (!prop->set) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - (*prop->set) (path, &iter, data->user_data); - } - else - { - if (!prop->get) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - (*prop->get) (path, &iter, data->user_data); - } - dbus_connection_send (bus, reply, NULL); - dbus_message_unref (reply); - return DBUS_HANDLER_RESULT_HANDLED; + 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); } -DBusHandlerResult -droute_message (DBusConnection * bus, DBusMessage * message, void *user_data) +static void * +path_get_datum (DRoutePath *path, const gchar *pathstr) { - DRouteData *data = (DRouteData *) user_data; - DRouteInterface *iface_def; - DRouteMethod *method; - const char *iface = dbus_message_get_interface (message); - const char *member = dbus_message_get_member (message); - int type; - DBusError error; - DBusMessage *reply; - - dbus_error_init (&error); - if (!member) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (iface && !strcmp (iface, "org.freedesktop.DBus.Properties")) - { - if (!strcmp (member, "GetAll")) - return prop_get_all (bus, message, data); - return prop (bus, message, data); - } - if (iface) - { - iface_def = find_iface (data, iface); - if (!iface_def) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (iface_def->methods) - for (method = iface_def->methods; method->func; method++) - { - if (!strcmp (method->name, member)) - { - reply = - (*method->func) (bus, message, - (method->wants_droute_data ? data : data-> - user_data)); - if (reply) - { - dbus_connection_send (bus, reply, NULL); - dbus_message_unref (reply); - } - return DBUS_HANDLER_RESULT_HANDLED; - } - } - } - else - { - GSList *l; - if (type == DBUS_MESSAGE_TYPE_SIGNAL) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - for (l = data->interfaces; l; l = g_slist_next (l)) - { - iface_def = (DRouteInterface *) l->data; - if (iface_def->methods) - for (method = iface_def->methods; method->func; method++) - { - if (!strcmp (method->name, member)) - { - reply = (*method->func) (bus, message, data->user_data); - if (reply) - { - dbus_connection_send (bus, reply, NULL); - dbus_message_unref (reply); - } - return DBUS_HANDLER_RESULT_HANDLED; - } - } - } - } - return DBUS_HANDLER_RESULT_HANDLED; + if (path->get_datum != NULL) + return (path->get_datum) (pathstr, path->user_data); + else + return path->user_data; } -dbus_bool_t -droute_return_v_int32 (DBusMessageIter * iter, dbus_int32_t val) +/*---------------------------------------------------------------------------*/ + +DRouteContext * +droute_new (DBusConnection *bus, const char *introspect_dir) { - DBusMessageIter sub; + DRouteContext *cnx; - 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; + cnx = g_new0 (DRouteContext, 1); + cnx->bus = bus; + cnx->registered_paths = g_ptr_array_new (); + cnx->introspect_dir = g_strdup(introspect_dir); } -dbus_bool_t -droute_return_v_double (DBusMessageIter * iter, double val) +void +droute_free (DRouteContext *cnx) { - DBusMessageIter sub; + g_pointer_array_foreach ((GFunc) path_free, cnx->registered_paths, NULL); + g_free (cnx->introspect_dir); + g_free (cnx); +} - 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; +/*---------------------------------------------------------------------------*/ + +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; + + new_path = path_new (cnx, (void *) data, NULL); + + if (!dbus_connection_register_object_path (cnx->bus, path, &droute_vtable, new_path)) + oom(); + + g_ptr_array_add (cnx->registered_paths, new_path); + return new_path; } -/* Return a string in a variant - * will return an empty string if passed a NULL value */ -dbus_bool_t -droute_return_v_string (DBusMessageIter * iter, const char *val) +DRoutePath * +droute_add_many (DRouteContext *cnx, + const char *path, + const void *data, + const DRouteGetDatumFunction get_datum) { - DBusMessageIter sub; + DRoutePath *new_path; - 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; + 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; } -dbus_int32_t -droute_get_v_int32 (DBusMessageIter * iter) +/*---------------------------------------------------------------------------*/ + +void +droute_path_add_interface(DRoutePath *path, + const char *name, + const DRouteMethod *methods, + const DRouteProperty *properties) { - DBusMessageIter sub; - dbus_int32_t rv; + 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->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); + } - // TODO- ensure we have the correct type - dbus_message_iter_recurse (iter, &sub); - dbus_message_iter_get_basic (&sub, &rv); - return rv; + for (; 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); + } } -const char * -droute_get_v_string (DBusMessageIter * iter) +/*---------------------------------------------------------------------------*/ + +/* 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 sub; - char *rv; + 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); - // TODO- ensure we have the correct type - dbus_message_iter_recurse (iter, &sub); - dbus_message_iter_get_basic (&sub, &rv); - return rv; + 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_strcmp (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; } -dbus_bool_t -droute_return_v_object (DBusMessageIter * iter, const char *path) +static DBusMessage * +impl_prop_GetSet (DBusMessage *message, + DRoutePath *path, + const char *pathstr, + gboolean get) { - DBusMessageIter sub; + DBusMessage *reply = NULL; + DBusError error; - 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; + StrPair pair; + PropertyPair *prop_funcs; + + 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); + + 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; + + reply = dbus_message_new_method_return (message); + dbus_message_iter_init_append (reply, &iter); + (prop_funcs->get) (&iter, datum); + } + else if (!get && prop_funcs->set) + { + void *datum = path_get_datum (path, pathstr); + DBusMessageIter iter; + + dbus_message_iter_init_append (message, &iter); + /* Skip the interface and property name */ + dbus_message_iter_next(&iter); + dbus_message_iter_next(&iter); + (prop_funcs->get) (&iter, datum); + } + return reply; } -dbus_bool_t -droute_add_interface (DRouteData * data, const char *name, - DRouteMethod * methods, DRouteProperty * properties, - DRouteGetDatumFunction get_datum, - DRouteFreeDatumFunction free_datum) +static DBusHandlerResult +handle_properties (DBusConnection *bus, + DBusMessage *message, + DRoutePath *path, + const gchar *iface, + const gchar *member, + const gchar *pathstr) { - DRouteInterface *iface = - (DRouteInterface *) malloc (sizeof (DRouteInterface)); - GSList *new_list; - - if (!iface) - return FALSE; - iface->name = strdup (name); - if (!iface->name) + 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; + + 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)) { - free (iface); - return FALSE; + g_string_append_len (str, contents, len); } - iface->methods = methods; - iface->properties = properties; - iface->get_datum = get_datum; - iface->free_datum = free_datum; - new_list = g_slist_append (data->interfaces, iface); - if (!new_list) + else { - free (iface->name); - free (iface); - return FALSE; + g_warning ("AT-SPI: Cannot find introspection XML file %s - %s", + filename, err->message); + g_error_free (err); } - data->interfaces = new_list; - return TRUE; + + g_string_append (str, "\n"); + g_free (filename); + g_free (contents); } + +static DBusHandlerResult +handle_intropsection (DBusConnection *bus, + DBusMessage *message, + DRoutePath *path, + const gchar *iface, + const gchar *member, + const gchar *pathstr) +{ + GString *output; + gchar *final; + gint i; + + DBusMessage *reply; + + if (g_strcmp (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; + + pair.one = iface; + pair.two = member; + + 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) + { + dbus_connection_send (bus, reply, NULL); + dbus_message_unref (reply); + } + result = DBUS_HANDLER_RESULT_HANDLED; + } + 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); +} + +/*END------------------------------------------------------------------------*/ diff --git a/droute/droute.h b/droute/droute.h index c3006cc..93de4f7 100644 --- a/droute/droute.h +++ b/droute/droute.h @@ -3,6 +3,7 @@ * (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 @@ -23,60 +24,59 @@ #define _DROUTE_H #include -#include "glib.h" /* needed for GString */ +#include -#define DROUTE_METHOD 0 -#define DROUTE_SIGNAL 1 +#include -typedef DBusMessage *(*DRouteFunction)(DBusConnection *, DBusMessage *, void *); -typedef dbus_bool_t (*DRoutePropertyFunction)(const char *, DBusMessageIter *, void *); +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; - dbus_bool_t wants_droute_data; + DRouteFunction func; + const char *name; }; typedef struct _DRouteProperty DRouteProperty; struct _DRouteProperty { - DRoutePropertyFunction get; - DRoutePropertyFunction set; - const char *name; + DRoutePropertyFunction get; + DRoutePropertyFunction set; + const char *name; }; - typedef void *(*DRouteGetDatumFunction)(const char *, void *); - typedef void (*DRouteFreeDatumFunction)(void *); +/*---------------------------------------------------------------------------*/ -typedef struct _DRouteInterface DRouteInterface; -struct _DRouteInterface -{ - DRouteMethod *methods; - DRouteProperty *properties; - DRouteGetDatumFunction get_datum; - DRouteFreeDatumFunction free_datum; - char *name; -}; +typedef struct _DRouteContext DRouteContext; -typedef struct _DRouteData DRouteData; -struct _DRouteData -{ - DBusConnection *bus; - GSList *interfaces; - char (*introspect_children)(const char *, GString *, void *); - void *user_data; -}; +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); -DBusHandlerResult droute_message(DBusConnection *bus, DBusMessage *message, void *user_data); +DRoutePath * +droute_add_many (DRouteContext *cnx, + const char *path, + const void *data, + const DRouteGetDatumFunction get_datum); -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_int32_t droute_get_v_int32(DBusMessageIter *iter); -const char *droute_get_v_string(DBusMessageIter *iter); -dbus_bool_t droute_return_v_object(DBusMessageIter *iter, const char *path); +void +droute_path_add_interface (DRoutePath *path, + const char *name, + const DRouteMethod *methods, + const DRouteProperty *properties); -dbus_bool_t droute_add_interface(DRouteData *data, const char *name, DRouteMethod *methods, DRouteProperty *properties, DRouteGetDatumFunction get_datum, DRouteFreeDatumFunction free_datum); -#endif /* _DROUTE_H */ +#endif /* _DROUTE_H */ diff --git a/droute/introspect-loader.c b/droute/introspect-loader.c deleted file mode 100644 index 723d3d6..0000000 --- a/droute/introspect-loader.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 - -/* - * This file contains utilities for loading introspection XML - * from the local file system. - * - * There is an installation directory with files containing introspection xml. - * Each file is named after the interface it describes. - */ - -/* - * Provides the path for the introspection directory. - */ -#if !defined ATSPI_INTROSPECTION_PATH - #error "No introspection XML directory defined" -#endif - -const char *spi_introspection_header = -"\n"; - -const char *spi_introspection_node_element = -"\n"; - -const char *spi_introspection_footer = -""; - -void -spi_append_interface (GString *str, const char *interface) -{ - char *filename; - char *contents; - char *introspection_directory; - gsize len; - - GError *err = NULL; - - introspection_directory = (char *) g_getenv("ATSPI_INTROSPECTION_PATH"); - if (introspection_directory == NULL) - introspection_directory = ATSPI_INTROSPECTION_PATH; - - filename = g_build_filename(introspection_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); -} -- 2.7.4