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