-
+/*
+ * Copyright 2008-2011 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 <stdio.h>
#include <stdarg.h>
+#include <sys/time.h>
+#include <string.h>
#include <glib.h>
#include "config.h"
#include "dbind/dbind.h"
+#include "atspi/atspi-gmain.h"
+
+static int dbind_timeout = -1;
/*
* FIXME: compare types - to ensure they match &
/*---------------------------------------------------------------------------*/
+typedef struct _SpiReentrantCallClosure
+{
+ DBusMessage *reply;
+} SpiReentrantCallClosure;
+
static void
-set_reply (DBusPendingCall *pending, void *user_data)
+set_reply (DBusPendingCall * pending, void *user_data)
{
- void **replyptr = (void **)user_data;
+ SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data;
- *replyptr = dbus_pending_call_steal_reply (pending);
+ closure->reply = dbus_pending_call_steal_reply (pending);
+ dbus_pending_call_unref (pending);
}
-static DBusMessage *
-send_and_allow_reentry (DBusConnection *bus, DBusMessage *message, DBusError *error)
+static gint
+time_elapsed (struct timeval *origin)
{
- DBusPendingCall *pending;
- DBusMessage *reply = NULL;
+ struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ return (tv.tv_sec - origin->tv_sec) * 1000 + (tv.tv_usec - origin->tv_usec) / 1000;
+}
- if (!dbus_connection_send_with_reply (bus, message, &pending, -1))
+DBusMessage *
+dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error)
+{
+ 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)
{
- return NULL;
+ 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;
}
- dbus_pending_call_set_notify (pending, set_reply, (void *)&reply, NULL);
- while (!reply)
+
+ closure = g_new0 (SpiReentrantCallClosure, 1);
+ closure->reply = NULL;
+ if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout)
+ || !pending)
{
- if (!dbus_connection_read_write_dispatch (bus, -1)) return NULL;
+ g_free (closure);
+ return NULL;
}
- return reply;
+ dbus_pending_call_set_notify (pending, set_reply, (void *) closure, g_free);
+
+ 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
DBusMessageIter iter;
DBusError *err, real_err;
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;
}
dbus_message_iter_init_append (msg, &iter);
dbind_any_marshal_va (&iter, &p, args);
- reply = send_and_allow_reentry (cnx, msg, err);
+ reply = dbind_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);
+ 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;
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;
}
/*---------------------------------------------------------------------------*/
+/* TODO: opt_error is unused; should be removed */
dbus_bool_t
dbind_emit_signal_va (DBusConnection *cnx,
const char *path,
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;
- }
+ const char *p;
msg = dbus_message_new_signal (path, interface, signal);
if (!msg)
if (msg)
dbus_message_unref (msg);
- if (err == &real_err)
- dbus_error_free (err);
-
return success;
}
return success;
}
+void
+dbind_set_timeout (int timeout)
+{
+ dbind_timeout = timeout;
+}
+
/*END------------------------------------------------------------------------*/