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