Fix check for message timeout
[platform/upstream/at-spi2-core.git] / dbind / dbind.c
1
2
3 #include <stdio.h>
4 #include <stdarg.h>
5 #include <sys/time.h>
6 #include <glib.h>
7
8 #include "config.h"
9 #include "dbind/dbind.h"
10
11 static int dbind_timeout = -1;
12
13 /*
14  * FIXME: compare types - to ensure they match &
15  *        do dynamic padding of structures etc.
16  */
17
18 /*---------------------------------------------------------------------------*/
19
20 typedef struct _SpiReentrantCallClosure 
21 {
22   DBusMessage *reply;
23 } SpiReentrantCallClosure;
24
25 static void
26 set_reply (DBusPendingCall * pending, void *user_data)
27 {
28   SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; 
29
30   closure->reply = dbus_pending_call_steal_reply (pending);
31   dbus_pending_call_unref (pending);
32 }
33
34 static gint
35 time_elapsed (struct timeval *origin)
36 {
37   struct timeval tv;
38
39   gettimeofday (&tv, NULL);
40   return (tv.tv_sec - origin->tv_sec) * 1000 + (tv.tv_usec - origin->tv_usec) / 1000;
41 }
42
43 DBusMessage *
44 dbind_send_and_allow_reentry (DBusConnection * bus, DBusMessage * message, DBusError *error)
45 {
46   DBusPendingCall *pending;
47   SpiReentrantCallClosure closure;
48   const char *unique_name = dbus_bus_get_unique_name (bus);
49   const char *destination = dbus_message_get_destination (message);
50   struct timeval tv;
51
52   if (unique_name && destination &&
53       strcmp (destination, unique_name) != 0)
54     return dbus_connection_send_with_reply_and_block (bus, message, dbind_timeout, error);
55
56   closure.reply = NULL;
57   dbus_connection_setup_with_g_main(bus, NULL);
58   if (!dbus_connection_send_with_reply (bus, message, &pending, dbind_timeout))
59       return NULL;
60   if (!pending)
61     return NULL;
62   dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL);
63
64   closure.reply = NULL;
65   gettimeofday (&tv, NULL);
66   while (!closure.reply)
67     {
68       if (!dbus_connection_read_write_dispatch (bus, dbind_timeout))
69         return NULL;
70 if (time_elapsed (&tv) > dbind_timeout)
71         return NULL;
72     }
73   
74   return closure.reply;
75 }
76
77 dbus_bool_t
78 dbind_method_call_reentrant_va (DBusConnection *cnx,
79                                 const char     *bus_name,
80                                 const char     *path,
81                                 const char     *interface,
82                                 const char     *method,
83                                 DBusError      *opt_error,
84                                 const char     *arg_types,
85                                 va_list         args)
86 {
87     dbus_bool_t success = FALSE;
88     DBusMessage *msg = NULL, *reply = NULL;
89     DBusMessageIter iter;
90     DBusError *err, real_err;
91     const char *p;
92   va_list args_demarshal;
93
94   va_copy (args_demarshal, args);
95     if (opt_error)
96         err = opt_error;
97     else {
98         dbus_error_init (&real_err);
99         err = &real_err;
100     }
101
102     msg = dbus_message_new_method_call (bus_name, path, interface, method);
103     if (!msg)
104         goto out;
105
106     p = arg_types;
107     dbus_message_iter_init_append (msg, &iter);
108     dbind_any_marshal_va (&iter, &p, args);
109
110     reply = dbind_send_and_allow_reentry (cnx, msg, err);
111     if (!reply)
112         goto out;
113
114     if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR)
115     {
116       const char *name = dbus_message_get_error_name (reply);
117       goto out;
118     }
119     /* demarshal */
120     if (p[0] == '=' && p[1] == '>')
121     {
122         DBusMessageIter iter;
123         dbus_message_iter_init (reply, &iter);
124         p = arg_types;
125         dbind_any_demarshal_va (&iter, &p, args_demarshal);
126     }
127
128     success = TRUE;
129 out:
130     if (msg)
131         dbus_message_unref (msg);
132
133     if (reply)
134         dbus_message_unref (reply);
135
136     if (err == &real_err)
137         dbus_error_free (err);
138
139     va_end (args_demarshal);
140     return success;
141 }
142
143 /**
144  * dbind_method_call_reentrant:
145  *
146  * @cnx:       A D-Bus Connection used to make the method call.
147  * @bus_name:  The D-Bus bus name of the program where the method call should
148  *             be made.
149  * @path:      The D-Bus object path that should handle the method.
150  * @interface: The D-Bus interface used to scope the method name.
151  * @method:    Method to be invoked.
152  * @opt_error: D-Bus error.
153  * @arg_types: Variable length arguments interleaving D-Bus argument types
154  *             and pointers to argument data.
155  *
156  * Makes a D-Bus method call using the supplied location data, method name and
157  * argument data.This function is re-entrant. It continuously reads from the D-Bus
158  * bus and dispatches messages until a reply has been recieved.
159  **/
160 dbus_bool_t
161 dbind_method_call_reentrant (DBusConnection *cnx,
162                              const char     *bus_name,
163                              const char     *path,
164                              const char     *interface,
165                              const char     *method,
166                              DBusError      *opt_error,
167                              const char     *arg_types,
168                              ...)
169 {
170     dbus_bool_t success = FALSE;
171     va_list args;
172
173     va_start (args, arg_types);
174     success = dbind_method_call_reentrant_va (cnx,
175                                               bus_name,
176                                               path,
177                                               interface,
178                                               method,
179                                               opt_error,
180                                               arg_types,
181                                               args);
182     va_end (args);
183
184     return success;
185 }
186
187 /*---------------------------------------------------------------------------*/
188
189 dbus_bool_t
190 dbind_emit_signal_va (DBusConnection *cnx,
191                       const char     *path,
192                       const char     *interface,
193                       const char     *signal,
194                       DBusError      *opt_error,
195                       const char     *arg_types,
196                       va_list         args)
197 {
198     dbus_bool_t success = FALSE;
199     DBusMessage *msg = NULL;
200     DBusMessageIter iter;
201     DBusError *err, real_err;
202     const char *p;
203
204     if (opt_error)
205         err = opt_error;
206     else {
207         dbus_error_init (&real_err);
208         err = &real_err;
209     }
210
211     msg = dbus_message_new_signal (path, interface, signal);
212     if (!msg)
213         goto out;
214
215     p = arg_types;
216     dbus_message_iter_init_append (msg, &iter);
217     dbind_any_marshal_va (&iter, &p, args);
218
219     if (!dbus_connection_send (cnx, msg, NULL))
220        goto out;
221
222     success = TRUE;
223 out:
224
225     if (msg)
226         dbus_message_unref (msg);
227
228     if (err == &real_err)
229         dbus_error_free (err);
230
231     return success;
232 }
233
234 /**
235  * dbind_emit_signal:
236  *
237  * @cnx:       A D-Bus Connection used to make the method call.
238  * @path:      The D-Bus object path that this signal is emitted from.
239  * @interface: The D-Bus interface used to scope the method name.
240  * @signal:    Name of signal to emit.
241  * @opt_error: D-Bus error.
242  * @arg_types: Variable length arguments interleaving D-Bus argument types
243  *             and pointers to argument data.
244  *
245  * Emits a D-Bus signal  using the supplied signal name and argument data.
246  **/
247 dbus_bool_t
248 dbind_emit_signal (DBusConnection *cnx,
249                    const char     *path,
250                    const char     *interface,
251                    const char     *signal,
252                    DBusError      *opt_error,
253                    const char     *arg_types,
254                    ...)
255 {
256     dbus_bool_t success = FALSE;
257     va_list args;
258
259     va_start (args, arg_types);
260     success = dbind_emit_signal_va (cnx, path, interface, signal, opt_error, arg_types, args);
261     va_end (args);
262
263     return success;
264 }
265 void
266 dbind_set_timeout (int timeout)
267 {
268   dbind_timeout = timeout;
269 }
270
271
272 /*END------------------------------------------------------------------------*/