X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbind%2Fdbind.c;h=e154f8571a3a8c79f646c1b497cd841a52e79130;hb=3785cfb93aa4a29b70ffdd39686f14d2c8e26b0b;hp=39b02407f0040cfddfcb2fce25e252ea8132845a;hpb=7b003b0e8fcc35db8c094af3c5f7faaeab9f42f1;p=platform%2Fupstream%2Fat-spi2-core.git diff --git a/dbind/dbind.c b/dbind/dbind.c index 39b0240..e154f85 100644 --- a/dbind/dbind.c +++ b/dbind/dbind.c @@ -1,245 +1,187 @@ -#include "config.h" +/* + * Copyright 2008-2011 Novell, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + #include -#define DBUS_API_SUBJECT_TO_CHANGE -#include -#include -#include #include +#include +#include +#include + +#include "config.h" +#include "dbind/dbind.h" +#include "atspi/atspi-gmain.h" + +static int dbind_timeout = -1; /* * 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) +typedef struct _SpiReentrantCallClosure { - 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; -} + DBusMessage *reply; +} SpiReentrantCallClosure; -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, - ...) +static void +set_reply (DBusPendingCall * pending, void *user_data) { - dbus_bool_t success; - va_list args; + SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; - 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; + closure->reply = dbus_pending_call_steal_reply (pending); + dbus_pending_call_unref (pending); } -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, - ...) +static gint +time_elapsed (struct timeval *origin) { - 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); + struct timeval tv; - va_end (args); - - return success; + gettimeofday (&tv, NULL); + return (tv.tv_sec - origin->tv_sec) * 1000 + (tv.tv_usec - origin->tv_usec) / 1000; } -static void set_reply (DBusPendingCall *pending, void *user_data) +DBusMessage * +dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error) { - void **replyptr = (void **)user_data; + DBusPendingCall *pending; + SpiReentrantCallClosure *closure; + const char *unique_name = dbus_bus_get_unique_name (bus); + const char *destination = dbus_message_get_destination (message); + struct timeval tv; + DBusMessage *ret; + static gboolean in_dispatch = FALSE; + + if (unique_name && destination && + strcmp (destination, unique_name) != 0) + { + ret = dbus_connection_send_with_reply_and_block (bus, message, + dbind_timeout, error); + if (g_main_depth () == 0 && !in_dispatch) + { + in_dispatch = TRUE; + while (dbus_connection_dispatch (bus) == DBUS_DISPATCH_DATA_REMAINS); + in_dispatch = FALSE; + } + return ret; + } - *replyptr = dbus_pending_call_steal_reply (pending); -} + closure = g_new0 (SpiReentrantCallClosure, 1); + closure->reply = NULL; + if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout) + || !pending) + { + g_free (closure); + return NULL; + } + dbus_pending_call_set_notify (pending, set_reply, (void *) closure, g_free); -static DBusMessage * -send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, int timeout, 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; + closure->reply = NULL; + gettimeofday (&tv, NULL); + dbus_pending_call_ref (pending); + while (!closure->reply) + { + if (!dbus_connection_read_write_dispatch (bus, dbind_timeout)) + { + //dbus_pending_call_set_notify (pending, NULL, NULL, NULL); + dbus_pending_call_cancel (pending); + dbus_pending_call_unref (pending); + return NULL; + } + if (time_elapsed (&tv) > dbind_timeout) + { + //dbus_pending_call_set_notify (pending, NULL, NULL, NULL); + dbus_pending_call_cancel (pending); + dbus_pending_call_unref (pending); + dbus_set_error_const (error, "org.freedesktop.DBus.Error.NoReply", + "timeout from dbind"); + return NULL; + } + } + + ret = closure->reply; + dbus_pending_call_unref (pending); + return ret; } 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_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; - char *p; + const char *p; + va_list args_demarshal; + + dbus_error_init (&real_err); + va_copy (args_demarshal, args); 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; - 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); - } - } + p = arg_types; + dbus_message_iter_init_append (msg, &iter); + dbind_any_marshal_va (&iter, &p, args); - if (!strcmp (dbus_bus_get_unique_name(cnx), dbus_message_get_destination(msg))) - { - /* 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 = dbind_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); - 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); - for (;*p != '\0';) { - void *arg = va_arg (args, void *); - dbind_any_demarshal (&iter, &p, &arg); - } + if (strcmp (p + 2, dbus_message_get_signature (reply)) != 0) + { + g_warning ("dbind: Call to \"%s\" returned signature %s; expected %s", + method, dbus_message_get_signature (reply), p + 2); + if (opt_error) + dbus_set_error (opt_error, DBUS_ERROR_INVALID_ARGS, + "Call to \"%s\" returned signature %s; expected %s", + method, dbus_message_get_signature (reply), + p + 2); + goto out; + } + p = arg_types; + dbind_any_demarshal_va (&iter, &p, args_demarshal); } success = TRUE; @@ -250,9 +192,130 @@ out: if (reply) dbus_message_unref (reply); - if (err == &real_err) - dbus_error_free (err); + if (dbus_error_is_set (&real_err)) + dbus_error_free (&real_err); + va_end (args_demarshal); 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; +} + +/*---------------------------------------------------------------------------*/ + +/* TODO: opt_error is unused; should be removed */ +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; + const char *p; + + 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); + + 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; +} +void +dbind_set_timeout (int timeout) +{ + dbind_timeout = timeout; +} + + +/*END------------------------------------------------------------------------*/