1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gproxy.c Proxy for remote objects
3 *
4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5 * Copyright (C) 2005 Nokia
6 *
7 * SPDX-License-Identifier: AFL-2.1 OR GPL-2.0-or-later
8 *
9 * Licensed under the Academic Free License version 2.1
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27 #include <config.h>
28
29 #include <dbus/dbus-glib.h>
30 #include <dbus/dbus-glib-lowlevel.h>
31 #include <dbus/dbus-signature.h>
32 #include "dbus-gutils.h"
33 #include "dbus-gsignature.h"
34 #include "dbus-gvalue.h"
35 #include "dbus-gvalue-utils.h"
36 #include "dbus-gobject.h"
37 #include <string.h>
38 #include <gobject/gvaluecollector.h>
39 #include <gio/gio.h>
40
41 #define DBUS_G_PROXY_CALL_TO_ID(x) (GPOINTER_TO_UINT(x))
42 #define DBUS_G_PROXY_ID_TO_CALL(x) (GUINT_TO_POINTER(x))
43 #define DBUS_G_PROXY_GET_PRIVATE(o) \
44 (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_TYPE_G_PROXY, DBusGProxyPrivate))
45
46 static void oom (void) G_GNUC_NORETURN;
47 static void
oom(void)48 oom (void)
49 {
50 g_error ("no memory");
51 }
52
53 typedef struct _DBusGProxyManager DBusGProxyManager;
54
55 typedef struct _DBusGProxyPrivate DBusGProxyPrivate;
56
57 struct _DBusGProxyPrivate
58 {
59 DBusGProxyManager *manager; /**< Proxy manager */
60 char *name; /**< Name messages go to or NULL */
61 char *path; /**< Path messages go to or NULL */
62 char *interface; /**< Interface messages go to or NULL */
63
64 DBusGProxyCall *name_call; /**< Pending call id to retrieve name owner */
65 guint for_owner : 1; /**< Whether or not this proxy is for a name owner */
66 guint associated : 1; /**< Whether or not this proxy is associated (for name proxies) */
67
68 /* FIXME: make threadsafe? */
69 guint call_id_counter; /**< Integer counter for pending calls */
70
71 GData *signal_signatures; /**< D-BUS signatures for each signal */
72
73 GHashTable *pending_calls; /**< Calls made on this proxy which have not yet returned */
74
75 int default_timeout; /**< Default timeout to use, see dbus_g_proxy_set_default_timeout */
76 };
77
78 static void dbus_g_proxy_init (DBusGProxy *proxy);
79 static void dbus_g_proxy_class_init (DBusGProxyClass *klass);
80 static GObject *dbus_g_proxy_constructor (GType type,
81 guint n_construct_properties,
82 GObjectConstructParam *construct_properties);
83 static void dbus_g_proxy_set_property (GObject *object,
84 guint prop_id,
85 const GValue *value,
86 GParamSpec *pspec);
87 static void dbus_g_proxy_get_property (GObject *object,
88 guint prop_id,
89 GValue *value,
90 GParamSpec *pspec);
91
92 static void dbus_g_proxy_finalize (GObject *object);
93 static void dbus_g_proxy_dispose (GObject *object);
94 static void dbus_g_proxy_destroy (DBusGProxy *proxy);
95 static void dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
96 DBusMessage *message);
97
98 static DBusGProxyCall *manager_begin_bus_call (DBusGProxyManager *manager,
99 const char *method,
100 DBusGProxyCallNotify notify,
101 gpointer data,
102 GDestroyNotify destroy,
103 GType first_arg_type,
104 ...);
105 static guint dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
106 const char *method,
107 DBusGProxyCallNotify notify,
108 gpointer data,
109 GDestroyNotify destroy,
110 GValueArray *args,
111 int timeout );
112 static gboolean dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
113 guint call_id,
114 GError **error,
115 GType first_arg_type,
116 va_list args);
117
118 /*
119 * A list of proxies with a given name+path+interface, used to
120 * route incoming signals.
121 */
122 typedef struct
123 {
124 GSList *proxies; /**< The list of proxies */
125
126 char name[4]; /**< name (empty string for none), nul byte,
127 * path, nul byte,
128 * interface, nul byte
129 */
130
131 } DBusGProxyList;
132
133 /*
134 * DBusGProxyManager's primary task is to route signals to the proxies
135 * those signals are emitted on. In order to do this it also has to
136 * track the owners of the names proxies are bound to.
137 */
138 struct _DBusGProxyManager
139 {
140 GStaticMutex lock; /**< Thread lock */
141 int refcount; /**< Reference count */
142 DBusConnection *connection; /**< Connection we're associated with. */
143
144 DBusGProxy *bus_proxy; /**< Special internal proxy used to talk to the bus */
145
146 GHashTable *proxy_lists; /**< Hash used to route incoming signals
147 * and iterate over proxies
148 * tristring -> DBusGProxyList
149 */
150 GHashTable *owner_match_rules; /**< Hash to keep track of match rules of
151 * NameOwnerChanged.
152 * gchar *name -> guint *refcount
153 */
154 GHashTable *owner_names; /**< Hash to keep track of mapping from
155 * char * -> GSList of DBusGProxyNameOwnerInfo
156 * base name -> [name,name,...] for proxies which
157 * are for names.
158 */
159 GSList *unassociated_proxies; /**< List of name proxies for which
160 * there was no result for
161 * GetNameOwner
162 */
163 };
164
165 static DBusGProxyManager *dbus_g_proxy_manager_ref (DBusGProxyManager *manager);
166 static DBusHandlerResult dbus_g_proxy_manager_filter (DBusConnection *connection,
167 DBusMessage *message,
168 void *user_data);
169
170
171 /** Lock the DBusGProxyManager */
172 #define LOCK_MANAGER(mgr) (g_static_mutex_lock (&(mgr)->lock))
173 /** Unlock the DBusGProxyManager */
174 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
175
176 static int g_proxy_manager_slot = -1;
177
178 /* Lock controlling get/set manager as data on each connection */
179 static GStaticMutex connection_g_proxy_lock = G_STATIC_MUTEX_INIT;
180
181 static DBusGProxyManager*
dbus_g_proxy_manager_get(DBusConnection * connection)182 dbus_g_proxy_manager_get (DBusConnection *connection)
183 {
184 DBusGProxyManager *manager;
185
186 dbus_connection_allocate_data_slot (&g_proxy_manager_slot);
187 if (g_proxy_manager_slot < 0)
188 g_error ("out of memory");
189
190 g_static_mutex_lock (&connection_g_proxy_lock);
191
192 manager = dbus_connection_get_data (connection, g_proxy_manager_slot);
193 if (manager != NULL)
194 {
195 dbus_connection_free_data_slot (&g_proxy_manager_slot);
196 dbus_g_proxy_manager_ref (manager);
197 g_static_mutex_unlock (&connection_g_proxy_lock);
198 return manager;
199 }
200
201 manager = g_new0 (DBusGProxyManager, 1);
202
203 manager->refcount = 1;
204 manager->connection = connection;
205
206 g_static_mutex_init (&manager->lock);
207
208 /* Proxy managers keep the connection alive, which means that
209 * DBusGProxy indirectly does. To free a connection you have to free
210 * all the proxies referring to it.
211 */
212 dbus_connection_ref (manager->connection);
213
214 dbus_connection_set_data (connection, g_proxy_manager_slot,
215 manager, NULL);
216
217 dbus_connection_add_filter (connection, dbus_g_proxy_manager_filter,
218 manager, NULL);
219
220 g_static_mutex_unlock (&connection_g_proxy_lock);
221
222 return manager;
223 }
224
225 static DBusGProxyManager *
dbus_g_proxy_manager_ref(DBusGProxyManager * manager)226 dbus_g_proxy_manager_ref (DBusGProxyManager *manager)
227 {
228 g_assert (manager != NULL);
229 g_assert (manager->refcount > 0);
230
231 LOCK_MANAGER (manager);
232
233 manager->refcount += 1;
234
235 UNLOCK_MANAGER (manager);
236
237 return manager;
238 }
239
240 static void
dbus_g_proxy_manager_unref(DBusGProxyManager * manager)241 dbus_g_proxy_manager_unref (DBusGProxyManager *manager)
242 {
243 g_assert (manager != NULL);
244 g_assert (manager->refcount > 0);
245
246 LOCK_MANAGER (manager);
247 manager->refcount -= 1;
248 if (manager->refcount == 0)
249 {
250 UNLOCK_MANAGER (manager);
251
252 if (manager->bus_proxy)
253 g_object_unref (manager->bus_proxy);
254
255 if (manager->proxy_lists)
256 {
257 /* can't have any proxies left since they hold
258 * a reference to the proxy manager.
259 */
260 g_assert (g_hash_table_size (manager->proxy_lists) == 0);
261
262 g_hash_table_destroy (manager->proxy_lists);
263 manager->proxy_lists = NULL;
264
265 }
266
267 if (manager->owner_match_rules)
268 {
269 /* Since we destroyed all proxies, none can be tracking
270 * name owners
271 */
272 g_assert (g_hash_table_size (manager->owner_match_rules) == 0);
273 g_hash_table_destroy (manager->owner_match_rules);
274 manager->owner_match_rules = NULL;
275 }
276
277 if (manager->owner_names)
278 {
279 /* Since we destroyed all proxies, none can be tracking
280 * name owners
281 */
282 g_assert (g_hash_table_size (manager->owner_names) == 0);
283
284 g_hash_table_destroy (manager->owner_names);
285 manager->owner_names = NULL;
286 }
287
288 g_assert (manager->unassociated_proxies == NULL);
289
290 g_static_mutex_free (&manager->lock);
291
292 g_static_mutex_lock (&connection_g_proxy_lock);
293
294 dbus_connection_remove_filter (manager->connection, dbus_g_proxy_manager_filter,
295 manager);
296
297 dbus_connection_set_data (manager->connection,
298 g_proxy_manager_slot,
299 NULL, NULL);
300
301 g_static_mutex_unlock (&connection_g_proxy_lock);
302
303 dbus_connection_unref (manager->connection);
304 g_free (manager);
305
306 dbus_connection_free_data_slot (&g_proxy_manager_slot);
307 }
308 else
309 {
310 UNLOCK_MANAGER (manager);
311 }
312 }
313
314 static guint
tristring_hash(gconstpointer key)315 tristring_hash (gconstpointer key)
316 {
317 const char *p = key;
318 guint h = *p;
319
320 if (h)
321 {
322 for (p += 1; *p != '\0'; p++)
323 h = (h << 5) - h + *p;
324 }
325
326 /* skip nul and do the next substring */
327 for (p += 1; *p != '\0'; p++)
328 h = (h << 5) - h + *p;
329
330 /* skip nul again and another substring */
331 for (p += 1; *p != '\0'; p++)
332 h = (h << 5) - h + *p;
333
334 return h;
335 }
336
337 static gboolean
strequal_len(const char * a,const char * b,size_t * lenp)338 strequal_len (const char *a,
339 const char *b,
340 size_t *lenp)
341 {
342 size_t a_len;
343 size_t b_len;
344
345 a_len = strlen (a);
346 b_len = strlen (b);
347
348 if (a_len != b_len)
349 return FALSE;
350
351 if (memcmp (a, b, a_len) != 0)
352 return FALSE;
353
354 *lenp = a_len;
355
356 return TRUE;
357 }
358
359 static gboolean
tristring_equal(gconstpointer a,gconstpointer b)360 tristring_equal (gconstpointer a,
361 gconstpointer b)
362 {
363 const char *ap = a;
364 const char *bp = b;
365 size_t len;
366
367 if (!strequal_len (ap, bp, &len))
368 return FALSE;
369
370 ap += len + 1;
371 bp += len + 1;
372
373 if (!strequal_len (ap, bp, &len))
374 return FALSE;
375
376 ap += len + 1;
377 bp += len + 1;
378
379 if (strcmp (ap, bp) != 0)
380 return FALSE;
381
382 return TRUE;
383 }
384
385 static char*
tristring_alloc_from_strings(size_t padding_before,const char * name,const char * path,const char * interface)386 tristring_alloc_from_strings (size_t padding_before,
387 const char *name,
388 const char *path,
389 const char *interface)
390 {
391 size_t name_len, iface_len, path_len, len;
392 char *tri;
393
394 if (name)
395 name_len = strlen (name);
396 else
397 name_len = 0;
398
399 path_len = strlen (path);
400
401 iface_len = strlen (interface);
402
403 tri = g_malloc (padding_before + name_len + path_len + iface_len + 3);
404
405 len = padding_before;
406
407 if (name)
408 memcpy (&tri[len], name, name_len);
409
410 len += name_len;
411 tri[len] = '\0';
412 len += 1;
413
414 g_assert (len == (padding_before + name_len + 1));
415
416 memcpy (&tri[len], path, path_len);
417 len += path_len;
418 tri[len] = '\0';
419 len += 1;
420
421 g_assert (len == (padding_before + name_len + path_len + 2));
422
423 memcpy (&tri[len], interface, iface_len);
424 len += iface_len;
425 tri[len] = '\0';
426 len += 1;
427
428 g_assert (len == (padding_before + name_len + path_len + iface_len + 3));
429
430 return tri;
431 }
432
433 static char*
tristring_from_proxy(DBusGProxy * proxy)434 tristring_from_proxy (DBusGProxy *proxy)
435 {
436 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
437
438 return tristring_alloc_from_strings (0,
439 priv->name,
440 priv->path,
441 priv->interface);
442 }
443
444 static char*
tristring_from_message(DBusMessage * message)445 tristring_from_message (DBusMessage *message)
446 {
447 const char *path;
448 const char *interface;
449
450 path = dbus_message_get_path (message);
451 interface = dbus_message_get_interface (message);
452
453 g_assert (path);
454 g_assert (interface);
455
456 return tristring_alloc_from_strings (0,
457 dbus_message_get_sender (message),
458 path, interface);
459 }
460
461 static DBusGProxyList*
g_proxy_list_new(DBusGProxy * first_proxy)462 g_proxy_list_new (DBusGProxy *first_proxy)
463 {
464 DBusGProxyList *list;
465 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(first_proxy);
466
467 list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
468 priv->name,
469 priv->path,
470 priv->interface);
471 list->proxies = NULL;
472
473 return list;
474 }
475
476 static void
g_proxy_list_free(DBusGProxyList * list)477 g_proxy_list_free (DBusGProxyList *list)
478 {
479 /* we don't hold a reference to the proxies in the list,
480 * as they ref the GProxyManager
481 */
482 g_slist_free (list->proxies);
483
484 g_free (list);
485 }
486
487 static char*
g_proxy_get_signal_match_rule(DBusGProxy * proxy)488 g_proxy_get_signal_match_rule (DBusGProxy *proxy)
489 {
490 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
491 /* FIXME Escaping is required here */
492
493 if (priv->name)
494 return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
495 priv->name, priv->path, priv->interface);
496 else
497 return g_strdup_printf ("type='signal',path='%s',interface='%s'",
498 priv->path, priv->interface);
499 }
500
501 static char *
get_owner_match_rule(const gchar * name)502 get_owner_match_rule (const gchar *name)
503 {
504 return g_strdup_printf ("type='signal',sender='" DBUS_SERVICE_DBUS
505 "',path='" DBUS_PATH_DBUS
506 "',interface='" DBUS_INTERFACE_DBUS
507 "',member='NameOwnerChanged'"
508 ",arg0='%s'", name);
509 }
510
511 typedef struct
512 {
513 char *name;
514 guint refcount;
515 } DBusGProxyNameOwnerInfo;
516
517 static gint
find_name_in_info(gconstpointer a,gconstpointer b)518 find_name_in_info (gconstpointer a, gconstpointer b)
519 {
520 const DBusGProxyNameOwnerInfo *info = a;
521 const char *name = b;
522
523 return strcmp (info->name, name);
524 }
525
526 typedef struct
527 {
528 const char *name;
529 const char *owner;
530 DBusGProxyNameOwnerInfo *info;
531 } DBusGProxyNameOwnerForeachData;
532
533 static void
name_owner_foreach(gpointer key,gpointer val,gpointer data)534 name_owner_foreach (gpointer key, gpointer val, gpointer data)
535 {
536 const char *owner;
537 DBusGProxyNameOwnerForeachData *foreach_data;
538 GSList *names;
539 GSList *link;
540
541 owner = key;
542 names = val;
543 foreach_data = data;
544
545 if (foreach_data->owner != NULL)
546 return;
547
548 g_assert (foreach_data->info == NULL);
549
550 link = g_slist_find_custom (names, foreach_data->name, find_name_in_info);
551 if (link)
552 {
553 foreach_data->owner = owner;
554 foreach_data->info = link->data;
555 }
556 }
557
558 static gboolean
dbus_g_proxy_manager_lookup_name_owner(DBusGProxyManager * manager,const char * name,DBusGProxyNameOwnerInfo ** info,const char ** owner)559 dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager *manager,
560 const char *name,
561 DBusGProxyNameOwnerInfo **info,
562 const char **owner)
563 {
564 DBusGProxyNameOwnerForeachData foreach_data;
565
566 foreach_data.name = name;
567 foreach_data.owner = NULL;
568 foreach_data.info = NULL;
569
570 g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data);
571
572 *info = foreach_data.info;
573 *owner = foreach_data.owner;
574 return *info != NULL;
575 }
576
577 static void
insert_nameinfo(DBusGProxyManager * manager,const char * owner,DBusGProxyNameOwnerInfo * info)578 insert_nameinfo (DBusGProxyManager *manager,
579 const char *owner,
580 DBusGProxyNameOwnerInfo *info)
581 {
582 GSList *names;
583 gboolean insert;
584
585 names = g_hash_table_lookup (manager->owner_names, owner);
586
587 /* Only need to g_hash_table_insert the first time */
588 insert = (names == NULL);
589
590 names = g_slist_append (names, info);
591
592 if (insert)
593 g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
594 }
595
596 static void
dbus_g_proxy_manager_monitor_name_owner(DBusGProxyManager * manager,const char * owner,const char * name)597 dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager *manager,
598 const char *owner,
599 const char *name)
600 {
601 GSList *names;
602 GSList *link;
603 DBusGProxyNameOwnerInfo *nameinfo;
604
605 names = g_hash_table_lookup (manager->owner_names, owner);
606 link = g_slist_find_custom (names, name, find_name_in_info);
607
608 if (!link)
609 {
610 nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1);
611 nameinfo->name = g_strdup (name);
612 nameinfo->refcount = 1;
613
614 insert_nameinfo (manager, owner, nameinfo);
615 }
616 else
617 {
618 nameinfo = link->data;
619 nameinfo->refcount++;
620 }
621 }
622
623 static void
dbus_g_proxy_manager_unmonitor_name_owner(DBusGProxyManager * manager,const char * name)624 dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager *manager,
625 const char *name)
626 {
627 DBusGProxyNameOwnerInfo *info;
628 const char *owner;
629 gboolean ret;
630
631 ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner);
632 g_assert (ret);
633 g_assert (info != NULL);
634 g_assert (owner != NULL);
635
636 info->refcount--;
637 if (info->refcount == 0)
638 {
639 GSList *names;
640 GSList *link;
641
642 names = g_hash_table_lookup (manager->owner_names, owner);
643 link = g_slist_find_custom (names, name, find_name_in_info);
644 names = g_slist_delete_link (names, link);
645 if (names != NULL)
646 g_hash_table_insert (manager->owner_names, g_strdup (owner), names);
647 else
648 g_hash_table_remove (manager->owner_names, owner);
649
650 g_free (info->name);
651 g_free (info);
652 }
653 }
654
655 typedef struct
656 {
657 const char *name;
658 GSList *destroyed;
659 } DBusGProxyUnassociateData;
660
661 static void
unassociate_proxies(gpointer key,gpointer val,gpointer user_data)662 unassociate_proxies (gpointer key, gpointer val, gpointer user_data)
663 {
664 DBusGProxyList *list;
665 const char *name;
666 GSList *tmp;
667 DBusGProxyUnassociateData *data;
668
669 list = val;
670 data = user_data;
671 name = data->name;
672
673 for (tmp = list->proxies; tmp; tmp = tmp->next)
674 {
675 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
676 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
677 DBusGProxyManager *manager;
678
679 manager = priv->manager;
680
681 if (priv->name != NULL && !strcmp (priv->name, name))
682 {
683 if (!priv->for_owner)
684 {
685 /* If a service appeared and then vanished very quickly,
686 * it's conceivable we have an inflight request for
687 * GetNameOwner here. Cancel it.
688 * https://bugs.freedesktop.org/show_bug.cgi?id=18573
689 */
690 if (priv->name_call)
691 dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
692
693 priv->name_call = NULL;
694
695 priv->associated = FALSE;
696 manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy);
697 }
698 else
699 {
700 data->destroyed = g_slist_prepend (data->destroyed, proxy);
701 /* make contents of list into weak pointers in case the objects
702 * unref each other when disposing */
703 g_object_add_weak_pointer (G_OBJECT (proxy),
704 &(data->destroyed->data));
705 }
706 }
707 }
708 }
709
710 static void
dbus_g_proxy_manager_replace_name_owner(DBusGProxyManager * manager,const char * name,const char * prev_owner,const char * new_owner)711 dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager *manager,
712 const char *name,
713 const char *prev_owner,
714 const char *new_owner)
715 {
716 GSList *names;
717
718 if (prev_owner[0] == '\0')
719 {
720 GSList *tmp;
721 GSList *removed;
722
723 /* We have a new service, look at unassociated proxies */
724
725 removed = NULL;
726
727 for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next)
728 {
729 DBusGProxy *proxy = tmp->data;
730 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
731
732 if (!strcmp (priv->name, name))
733 {
734 removed = g_slist_prepend (removed, tmp);
735
736 dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name);
737 priv->associated = TRUE;
738 }
739 }
740
741 for (tmp = removed; tmp; tmp = tmp->next)
742 manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data);
743 g_slist_free (removed);
744 }
745 else
746 {
747 DBusGProxyNameOwnerInfo *info;
748 GSList *link;
749
750 /* Name owner changed or deleted */
751
752 names = g_hash_table_lookup (manager->owner_names, prev_owner);
753
754 info = NULL;
755 if (names != NULL)
756 {
757 link = g_slist_find_custom (names, name, find_name_in_info);
758
759 if (link != NULL)
760 {
761 info = link->data;
762
763 names = g_slist_delete_link (names, link);
764
765 if (names == NULL)
766 {
767 g_hash_table_remove (manager->owner_names, prev_owner);
768 }
769 else
770 {
771 g_hash_table_insert (manager->owner_names,
772 g_strdup (prev_owner), names);
773 }
774 }
775 }
776
777 if (new_owner[0] == '\0')
778 {
779 DBusGProxyUnassociateData data;
780 GSList *tmp;
781
782 data.name = name;
783 data.destroyed = NULL;
784
785 /* A service went away, we need to unassociate proxies */
786 g_hash_table_foreach (manager->proxy_lists,
787 unassociate_proxies, &data);
788
789 UNLOCK_MANAGER (manager);
790
791 /* the destroyed list's data pointers are weak pointers, so that we
792 * don't end up calling destroy on proxies which have already been
793 * freed up as a result of other ones being destroyed */
794 for (tmp = data.destroyed; tmp; tmp = tmp->next)
795 if (tmp->data != NULL)
796 {
797 g_object_remove_weak_pointer (G_OBJECT (tmp->data),
798 &(tmp->data));
799 dbus_g_proxy_destroy (tmp->data);
800 }
801 g_slist_free (data.destroyed);
802
803 LOCK_MANAGER (manager);
804
805 if (info)
806 {
807 g_free (info->name);
808 g_free (info);
809 }
810 }
811 else if (info)
812 {
813 insert_nameinfo (manager, new_owner, info);
814 }
815 }
816 }
817
818 static void
got_name_owner_cb(DBusGProxy * bus_proxy,DBusGProxyCall * call,void * user_data)819 got_name_owner_cb (DBusGProxy *bus_proxy,
820 DBusGProxyCall *call,
821 void *user_data)
822 {
823 DBusGProxy *proxy = user_data;
824 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
825 GError *error;
826 char *owner;
827
828 error = NULL;
829 owner = NULL;
830
831 LOCK_MANAGER (priv->manager);
832
833 if (!dbus_g_proxy_end_call (bus_proxy, call, &error,
834 G_TYPE_STRING, &owner,
835 G_TYPE_INVALID))
836 {
837 if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER)
838 {
839 priv->manager->unassociated_proxies = g_slist_prepend (priv->manager->unassociated_proxies, proxy);
840 }
841 else if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION)
842 g_warning ("Couldn't get name owner (%s): %s",
843 dbus_g_error_get_name (error),
844 error->message);
845 else
846 g_warning ("Couldn't get name owner (code %d): %s",
847 error->code, error->message);
848 g_clear_error (&error);
849 goto out;
850 }
851 else
852 {
853 dbus_g_proxy_manager_monitor_name_owner (priv->manager, owner, priv->name);
854 priv->associated = TRUE;
855 }
856
857 out:
858 priv->name_call = NULL;
859 UNLOCK_MANAGER (priv->manager);
860 g_free (owner);
861 }
862
863 static char *
get_name_owner(DBusConnection * connection,const char * name,GError ** error)864 get_name_owner (DBusConnection *connection,
865 const char *name,
866 GError **error)
867 {
868 DBusError derror;
869 DBusMessage *request, *reply;
870 char *base_name;
871
872 dbus_error_init (&derror);
873
874 base_name = NULL;
875 reply = NULL;
876
877 request = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
878 DBUS_PATH_DBUS,
879 DBUS_INTERFACE_DBUS,
880 "GetNameOwner");
881 if (request == NULL)
882 g_error ("Out of memory");
883
884 if (!dbus_message_append_args (request,
885 DBUS_TYPE_STRING, &name,
886 DBUS_TYPE_INVALID))
887 g_error ("Out of memory");
888
889 reply =
890 dbus_connection_send_with_reply_and_block (connection,
891 request,
892 2000, &derror);
893 if (reply == NULL)
894 goto error;
895
896 if (dbus_set_error_from_message (&derror, reply))
897 goto error;
898
899 if (!dbus_message_get_args (reply, &derror,
900 DBUS_TYPE_STRING, &base_name,
901 DBUS_TYPE_INVALID))
902 goto error;
903
904 base_name = g_strdup (base_name);
905 goto out;
906
907 error:
908 g_assert (dbus_error_is_set (&derror));
909 dbus_set_g_error (error, &derror);
910 dbus_error_free (&derror);
911
912 out:
913 if (request)
914 dbus_message_unref (request);
915 if (reply)
916 dbus_message_unref (reply);
917
918 return base_name;
919 }
920
921
922 static void
guint_slice_free(gpointer data)923 guint_slice_free (gpointer data)
924 {
925 g_slice_free (guint, data);
926 }
927
928
929 static void
dbus_g_proxy_manager_register(DBusGProxyManager * manager,DBusGProxy * proxy)930 dbus_g_proxy_manager_register (DBusGProxyManager *manager,
931 DBusGProxy *proxy)
932 {
933 DBusGProxyList *list;
934 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
935
936 LOCK_MANAGER (manager);
937
938 if (manager->proxy_lists == NULL)
939 {
940 g_assert (manager->owner_names == NULL);
941 g_assert (manager->owner_match_rules == NULL);
942
943 list = NULL;
944 manager->proxy_lists = g_hash_table_new_full (tristring_hash,
945 tristring_equal,
946 NULL,
947 (GFreeFunc) g_proxy_list_free);
948 manager->owner_names = g_hash_table_new_full (g_str_hash,
949 g_str_equal,
950 g_free,
951 NULL);
952 manager->owner_match_rules = g_hash_table_new_full (g_str_hash,
953 g_str_equal,
954 g_free,
955 guint_slice_free);
956 }
957 else
958 {
959 char *tri;
960
961 tri = tristring_from_proxy (proxy);
962
963 list = g_hash_table_lookup (manager->proxy_lists, tri);
964
965 g_free (tri);
966 }
967
968 if (list == NULL)
969 {
970 list = g_proxy_list_new (proxy);
971
972 g_hash_table_replace (manager->proxy_lists,
973 list->name, list);
974 }
975
976 if (list->proxies == NULL && priv->name)
977 {
978 /* We have to add match rules to the server,
979 * but only if the server is a message bus,
980 * not if it's a peer.
981 */
982 char *rule;
983 guint *refcount;
984
985 rule = g_proxy_get_signal_match_rule (proxy);
986 /* We don't check for errors; it's not like anyone would handle them, and
987 * we don't want a round trip here.
988 */
989 dbus_bus_add_match (manager->connection, rule, NULL);
990 g_free (rule);
991
992 refcount = g_hash_table_lookup (manager->owner_match_rules, priv->name);
993
994 if (refcount != NULL)
995 {
996 g_assert (*refcount != 0);
997 g_assert (*refcount < G_MAXUINT);
998 (*refcount)++;
999 }
1000 else
1001 {
1002 char *rule;
1003 rule = get_owner_match_rule (priv->name);
1004 dbus_bus_add_match (manager->connection,
1005 rule, NULL);
1006 g_free (rule);
1007
1008 refcount = g_slice_new (guint);
1009 *refcount = 1;
1010 g_hash_table_insert (manager->owner_match_rules,
1011 g_strdup (priv->name), refcount);
1012 }
1013 }
1014
1015 g_assert (g_slist_find (list->proxies, proxy) == NULL);
1016
1017 list->proxies = g_slist_prepend (list->proxies, proxy);
1018
1019 if (!priv->for_owner)
1020 {
1021 const char *owner;
1022 DBusGProxyNameOwnerInfo *info;
1023
1024 if (!dbus_g_proxy_manager_lookup_name_owner (manager, priv->name, &info, &owner))
1025 {
1026 priv->name_call = manager_begin_bus_call (manager, "GetNameOwner",
1027 got_name_owner_cb,
1028 proxy, NULL,
1029 G_TYPE_STRING,
1030 priv->name,
1031 G_TYPE_INVALID);
1032
1033 priv->associated = FALSE;
1034 }
1035 else
1036 {
1037 info->refcount++;
1038 priv->associated = TRUE;
1039 }
1040 }
1041
1042 UNLOCK_MANAGER (manager);
1043 }
1044
1045 static void
dbus_g_proxy_manager_unregister(DBusGProxyManager * manager,DBusGProxy * proxy)1046 dbus_g_proxy_manager_unregister (DBusGProxyManager *manager,
1047 DBusGProxy *proxy)
1048 {
1049 DBusGProxyList *list;
1050 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1051 char *tri;
1052
1053 LOCK_MANAGER (manager);
1054
1055 #ifndef G_DISABLE_CHECKS
1056 if (manager->proxy_lists == NULL)
1057 {
1058 g_warning ("Trying to unregister a proxy but there aren't any registered");
1059 return;
1060 }
1061 #endif
1062
1063 tri = tristring_from_proxy (proxy);
1064
1065 list = g_hash_table_lookup (manager->proxy_lists, tri);
1066
1067 #ifndef G_DISABLE_CHECKS
1068 if (list == NULL)
1069 {
1070 g_warning ("Trying to unregister a proxy but it isn't registered");
1071 return;
1072 }
1073 #endif
1074
1075 g_assert (g_slist_find (list->proxies, proxy) != NULL);
1076
1077 list->proxies = g_slist_remove (list->proxies, proxy);
1078
1079 g_assert (g_slist_find (list->proxies, proxy) == NULL);
1080
1081 if (!priv->for_owner)
1082 {
1083 if (!priv->associated)
1084 {
1085 GSList *link;
1086
1087 if (priv->name_call != 0)
1088 {
1089 dbus_g_proxy_cancel_call (manager->bus_proxy, priv->name_call);
1090 priv->name_call = 0;
1091 }
1092 else
1093 {
1094 link = g_slist_find (manager->unassociated_proxies, proxy);
1095 if (link != NULL)
1096 {
1097 manager->unassociated_proxies = g_slist_delete_link (
1098 manager->unassociated_proxies, link);
1099 }
1100 }
1101 }
1102 else
1103 {
1104 g_assert (priv->name_call == 0);
1105
1106 dbus_g_proxy_manager_unmonitor_name_owner (manager, priv->name);
1107 }
1108 }
1109
1110 if (list->proxies == NULL)
1111 {
1112 char *rule;
1113 g_hash_table_remove (manager->proxy_lists,
1114 tri);
1115
1116 rule = g_proxy_get_signal_match_rule (proxy);
1117 dbus_bus_remove_match (manager->connection,
1118 rule, NULL);
1119 g_free (rule);
1120
1121 if (priv->name)
1122 {
1123 guint *refcount;
1124 refcount = g_hash_table_lookup (manager->owner_match_rules, priv->name);
1125 (*refcount)--;
1126
1127 if (*refcount == 0)
1128 {
1129 rule = get_owner_match_rule (priv->name);
1130 dbus_bus_remove_match (manager->connection,
1131 rule, NULL);
1132 g_free (rule);
1133 g_hash_table_remove (manager->owner_match_rules, priv->name);
1134 }
1135 }
1136 }
1137
1138 if (g_hash_table_size (manager->proxy_lists) == 0)
1139 {
1140 g_hash_table_destroy (manager->proxy_lists);
1141 manager->proxy_lists = NULL;
1142 }
1143
1144 if (manager->owner_match_rules != NULL &&
1145 g_hash_table_size (manager->owner_match_rules) == 0)
1146 {
1147 g_hash_table_destroy (manager->owner_match_rules);
1148 manager->owner_match_rules = NULL;
1149 }
1150
1151 g_free (tri);
1152
1153 UNLOCK_MANAGER (manager);
1154 }
1155
1156 static void
list_proxies_foreach(gpointer key,gpointer value,gpointer user_data)1157 list_proxies_foreach (gpointer key,
1158 gpointer value,
1159 gpointer user_data)
1160 {
1161 DBusGProxyList *list;
1162 GSList **ret;
1163 GSList *tmp;
1164
1165 list = value;
1166 ret = user_data;
1167
1168 tmp = list->proxies;
1169 while (tmp != NULL)
1170 {
1171 DBusGProxy *proxy = DBUS_G_PROXY (tmp->data);
1172
1173 g_object_ref (proxy);
1174 *ret = g_slist_prepend (*ret, proxy);
1175
1176 tmp = tmp->next;
1177 }
1178 }
1179
1180 static GSList*
dbus_g_proxy_manager_list_all(DBusGProxyManager * manager)1181 dbus_g_proxy_manager_list_all (DBusGProxyManager *manager)
1182 {
1183 GSList *ret;
1184
1185 ret = NULL;
1186
1187 if (manager->proxy_lists)
1188 {
1189 g_hash_table_foreach (manager->proxy_lists,
1190 list_proxies_foreach,
1191 &ret);
1192 }
1193
1194 return ret;
1195 }
1196
1197 static DBusHandlerResult
dbus_g_proxy_manager_filter(DBusConnection * connection,DBusMessage * message,void * user_data)1198 dbus_g_proxy_manager_filter (DBusConnection *connection,
1199 DBusMessage *message,
1200 void *user_data)
1201 {
1202 DBusGProxyManager *manager;
1203
1204 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
1205 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1206
1207 manager = user_data;
1208
1209 dbus_g_proxy_manager_ref (manager);
1210
1211 LOCK_MANAGER (manager);
1212
1213 if (dbus_message_is_signal (message,
1214 DBUS_INTERFACE_LOCAL,
1215 "Disconnected"))
1216 {
1217 /* Destroy all the proxies, quite possibly resulting in unreferencing
1218 * the proxy manager and the connection as well.
1219 */
1220 GSList *all;
1221 GSList *tmp;
1222
1223 all = dbus_g_proxy_manager_list_all (manager);
1224
1225 tmp = all;
1226 while (tmp != NULL)
1227 {
1228 DBusGProxy *proxy;
1229
1230 proxy = DBUS_G_PROXY (tmp->data);
1231
1232 UNLOCK_MANAGER (manager);
1233 dbus_g_proxy_destroy (proxy);
1234 g_object_unref (G_OBJECT (proxy));
1235 LOCK_MANAGER (manager);
1236
1237 tmp = tmp->next;
1238 }
1239
1240 g_slist_free (all);
1241
1242 #ifndef G_DISABLE_CHECKS
1243 if (manager->proxy_lists != NULL)
1244 g_warning ("Disconnection emitted \"destroy\" on all DBusGProxy, but somehow new proxies were created in response to one of those destroy signals. This will cause a memory leak.");
1245 #endif
1246 }
1247 else
1248 {
1249 char *tri;
1250 GSList *full_list;
1251 GSList *owned_names;
1252 GSList *tmp;
1253 const char *sender;
1254
1255 sender = dbus_message_get_sender (message);
1256
1257 /* First we handle NameOwnerChanged internally */
1258 if (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0 &&
1259 dbus_message_is_signal (message,
1260 DBUS_INTERFACE_DBUS,
1261 "NameOwnerChanged"))
1262 {
1263 const char *name;
1264 const char *prev_owner;
1265 const char *new_owner;
1266 DBusError derr;
1267
1268 dbus_error_init (&derr);
1269 if (!dbus_message_get_args (message,
1270 &derr,
1271 DBUS_TYPE_STRING,
1272 &name,
1273 DBUS_TYPE_STRING,
1274 &prev_owner,
1275 DBUS_TYPE_STRING,
1276 &new_owner,
1277 DBUS_TYPE_INVALID))
1278 {
1279 /* Ignore this error */
1280 dbus_error_free (&derr);
1281 }
1282 else if (manager->owner_names != NULL)
1283 {
1284 dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner);
1285 }
1286 }
1287
1288 /* dbus spec requires these, libdbus validates */
1289 g_assert (dbus_message_get_path (message) != NULL);
1290 g_assert (dbus_message_get_interface (message) != NULL);
1291 g_assert (dbus_message_get_member (message) != NULL);
1292
1293 tri = tristring_from_message (message);
1294
1295 if (manager->proxy_lists)
1296 {
1297 DBusGProxyList *owner_list;
1298 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1299 if (owner_list)
1300 full_list = g_slist_copy (owner_list->proxies);
1301 else
1302 full_list = NULL;
1303 }
1304 else
1305 full_list = NULL;
1306
1307 g_free (tri);
1308
1309 if (manager->owner_names && sender)
1310 {
1311 owned_names = g_hash_table_lookup (manager->owner_names, sender);
1312 for (tmp = owned_names; tmp; tmp = tmp->next)
1313 {
1314 DBusGProxyList *owner_list;
1315 DBusGProxyNameOwnerInfo *nameinfo;
1316
1317 nameinfo = tmp->data;
1318 g_assert (nameinfo->refcount > 0);
1319 tri = tristring_alloc_from_strings (0, nameinfo->name,
1320 dbus_message_get_path (message),
1321 dbus_message_get_interface (message));
1322
1323 owner_list = g_hash_table_lookup (manager->proxy_lists, tri);
1324 if (owner_list != NULL)
1325 {
1326 GSList *elt;
1327
1328 /* Ignore duplicates when adding to full_list */
1329 for (elt = owner_list->proxies; elt; elt = g_slist_next (elt))
1330 {
1331 if (!g_slist_find (full_list, elt->data))
1332 full_list = g_slist_append (full_list, elt->data);
1333 }
1334 }
1335 g_free (tri);
1336 }
1337 }
1338
1339 #if 0
1340 g_print ("proxy got %s,%s,%s = list %p\n",
1341 tri,
1342 tri + strlen (tri) + 1,
1343 tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
1344 list);
1345 #endif
1346
1347 /* Emit the signal */
1348
1349 g_slist_foreach (full_list, (GFunc) g_object_ref, NULL);
1350
1351 for (tmp = full_list; tmp; tmp = tmp->next)
1352 {
1353 DBusGProxy *proxy;
1354
1355 proxy = DBUS_G_PROXY (tmp->data);
1356
1357 UNLOCK_MANAGER (manager);
1358 dbus_g_proxy_emit_remote_signal (proxy, message);
1359 g_object_unref (G_OBJECT (proxy));
1360 LOCK_MANAGER (manager);
1361 }
1362 g_slist_free (full_list);
1363 }
1364
1365 UNLOCK_MANAGER (manager);
1366 dbus_g_proxy_manager_unref (manager);
1367
1368 /* "Handling" signals doesn't make sense, they are for everyone
1369 * who cares
1370 */
1371 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1372 }
1373
1374
1375
1376 /* ---------- DBusGProxy -------------- */
1377 #define DBUS_G_PROXY_DESTROYED(proxy) (DBUS_G_PROXY_GET_PRIVATE(proxy)->manager == NULL)
1378
1379 static void
1380 marshal_dbus_message_to_g_marshaller (GClosure *closure,
1381 GValue *return_value,
1382 guint n_param_values,
1383 const GValue *param_values,
1384 gpointer invocation_hint,
1385 gpointer marshal_data);
1386 enum
1387 {
1388 PROP_0,
1389 PROP_NAME,
1390 PROP_PATH,
1391 PROP_INTERFACE,
1392 PROP_CONNECTION
1393 };
1394
1395 enum
1396 {
1397 DESTROY,
1398 RECEIVED,
1399 LAST_SIGNAL
1400 };
1401
1402 static void *parent_class;
1403 static guint signals[LAST_SIGNAL] = { 0 };
1404
1405 static void
dbus_g_proxy_init(DBusGProxy * proxy)1406 dbus_g_proxy_init (DBusGProxy *proxy)
1407 {
1408 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1409
1410 g_datalist_init (&priv->signal_signatures);
1411 priv->pending_calls = g_hash_table_new_full (NULL, NULL, NULL,
1412 (GDestroyNotify) dbus_pending_call_unref);
1413 priv->name_call = 0;
1414 priv->associated = FALSE;
1415 priv->default_timeout = -1;
1416 }
1417
1418 static GObject *
dbus_g_proxy_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)1419 dbus_g_proxy_constructor (GType type,
1420 guint n_construct_properties,
1421 GObjectConstructParam *construct_properties)
1422 {
1423 DBusGProxy *proxy;
1424 DBusGProxyClass *klass;
1425 GObjectClass *parent_class;
1426 DBusGProxyPrivate *priv;
1427
1428 klass = DBUS_G_PROXY_CLASS (g_type_class_peek (DBUS_TYPE_G_PROXY));
1429
1430 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
1431
1432 proxy = DBUS_G_PROXY (parent_class->constructor (type, n_construct_properties,
1433 construct_properties));
1434
1435 priv = DBUS_G_PROXY_GET_PRIVATE (proxy);
1436
1437 /* if these assertions fail, a deriving class has not set our required
1438 * parameters - our own public constructors do return_if_fail checks
1439 * on these parameters being provided. unfortunately we can't assert
1440 * for manager because it's allowed to be NULL when tha mangager is
1441 * setting up a bus proxy for its own calls */
1442 g_assert (priv->path != NULL);
1443 g_assert (priv->interface != NULL);
1444
1445 if (priv->manager != NULL)
1446 {
1447 dbus_g_proxy_manager_register (priv->manager, proxy);
1448 }
1449
1450 return G_OBJECT (proxy);
1451 }
1452
1453 static void
dbus_g_proxy_class_init(DBusGProxyClass * klass)1454 dbus_g_proxy_class_init (DBusGProxyClass *klass)
1455 {
1456 GObjectClass *object_class = G_OBJECT_CLASS (klass);
1457
1458 parent_class = g_type_class_peek_parent (klass);
1459
1460 g_type_class_add_private (klass, sizeof (DBusGProxyPrivate));
1461
1462 object_class->set_property = dbus_g_proxy_set_property;
1463 object_class->get_property = dbus_g_proxy_get_property;
1464
1465 g_object_class_install_property (object_class,
1466 PROP_NAME,
1467 g_param_spec_string ("name",
1468 "name",
1469 "name",
1470 NULL,
1471 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1472
1473 g_object_class_install_property (object_class,
1474 PROP_PATH,
1475 g_param_spec_string ("path",
1476 "path",
1477 "path",
1478 NULL,
1479 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1480
1481 g_object_class_install_property (object_class,
1482 PROP_INTERFACE,
1483 g_param_spec_string ("interface",
1484 "interface",
1485 "interface",
1486 NULL,
1487 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1488
1489 g_object_class_install_property (object_class,
1490 PROP_CONNECTION,
1491 g_param_spec_boxed ("connection",
1492 "connection",
1493 "connection",
1494 DBUS_TYPE_G_CONNECTION,
1495 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1496
1497 object_class->finalize = dbus_g_proxy_finalize;
1498 object_class->dispose = dbus_g_proxy_dispose;
1499 object_class->constructor = dbus_g_proxy_constructor;
1500
1501 /**
1502 * DBusGProxy::destroy:
1503 * @dbusgproxy: the object which received the signal.
1504 *
1505 * Deprecated: New code should use #GDBusProxy instead.
1506 */
1507 signals[DESTROY] =
1508 g_signal_new ("destroy",
1509 G_OBJECT_CLASS_TYPE (object_class),
1510 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
1511 0,
1512 NULL, NULL,
1513 g_cclosure_marshal_VOID__VOID,
1514 G_TYPE_NONE, 0);
1515
1516 /*
1517 * DBusGProxy::received:
1518 * @dbusgproxy: the object which received the signal.
1519 *
1520 * Deprecated: New code should use #GDBusProxy instead.
1521 */
1522 signals[RECEIVED] =
1523 g_signal_new ("received",
1524 G_OBJECT_CLASS_TYPE (object_class),
1525 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
1526 0,
1527 NULL, NULL,
1528 marshal_dbus_message_to_g_marshaller,
1529 G_TYPE_NONE, 2, DBUS_TYPE_MESSAGE, G_TYPE_POINTER);
1530 }
1531
1532 static gboolean
cancel_pending_call(gpointer key,gpointer val,gpointer data)1533 cancel_pending_call (gpointer key, gpointer val, gpointer data)
1534 {
1535 DBusPendingCall *pending = val;
1536
1537 dbus_pending_call_cancel (pending);
1538
1539 return TRUE;
1540 }
1541
1542 static void
dbus_g_proxy_dispose(GObject * object)1543 dbus_g_proxy_dispose (GObject *object)
1544 {
1545 DBusGProxy *proxy = DBUS_G_PROXY (object);
1546 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1547
1548 if (priv->pending_calls == NULL)
1549 {
1550 return;
1551 }
1552
1553 /* Cancel outgoing pending calls */
1554 g_hash_table_foreach_remove (priv->pending_calls, cancel_pending_call, NULL);
1555 g_hash_table_destroy (priv->pending_calls);
1556 priv->pending_calls = NULL;
1557
1558 if (priv->manager && proxy != priv->manager->bus_proxy)
1559 {
1560 dbus_g_proxy_manager_unregister (priv->manager, proxy);
1561 dbus_g_proxy_manager_unref (priv->manager);
1562 }
1563 priv->manager = NULL;
1564
1565 g_datalist_clear (&priv->signal_signatures);
1566
1567 g_signal_emit (object, signals[DESTROY], 0);
1568
1569 G_OBJECT_CLASS (parent_class)->dispose (object);
1570 }
1571
1572 static void
dbus_g_proxy_finalize(GObject * object)1573 dbus_g_proxy_finalize (GObject *object)
1574 {
1575 DBusGProxy *proxy = DBUS_G_PROXY (object);
1576 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1577
1578 g_return_if_fail (DBUS_G_PROXY_DESTROYED (proxy));
1579
1580 g_free (priv->name);
1581 g_free (priv->path);
1582 g_free (priv->interface);
1583
1584 G_OBJECT_CLASS (parent_class)->finalize (object);
1585 }
1586
1587 static void
dbus_g_proxy_destroy(DBusGProxy * proxy)1588 dbus_g_proxy_destroy (DBusGProxy *proxy)
1589 {
1590 /* FIXME do we need the GTK_IN_DESTRUCTION style flag
1591 * from GtkObject?
1592 */
1593 g_object_run_dispose (G_OBJECT (proxy));
1594 }
1595
1596 static void
dbus_g_proxy_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1597 dbus_g_proxy_set_property (GObject *object,
1598 guint prop_id,
1599 const GValue *value,
1600 GParamSpec *pspec)
1601 {
1602 DBusGProxy *proxy = DBUS_G_PROXY (object);
1603 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1604 DBusGConnection *connection;
1605
1606 switch (prop_id)
1607 {
1608 case PROP_NAME:
1609 priv->name = g_strdup (g_value_get_string (value));
1610 if (priv->name)
1611 priv->for_owner = (priv->name[0] == ':');
1612 else
1613 priv->for_owner = TRUE;
1614 break;
1615 case PROP_PATH:
1616 priv->path = g_strdup (g_value_get_string (value));
1617 break;
1618 case PROP_INTERFACE:
1619 priv->interface = g_strdup (g_value_get_string (value));
1620 break;
1621 case PROP_CONNECTION:
1622 connection = g_value_get_boxed (value);
1623 if (connection != NULL)
1624 {
1625 priv->manager = dbus_g_proxy_manager_get (DBUS_CONNECTION_FROM_G_CONNECTION (connection));
1626 }
1627 break;
1628 default:
1629 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1630 break;
1631 }
1632 }
1633
1634 static void
dbus_g_proxy_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1635 dbus_g_proxy_get_property (GObject *object,
1636 guint prop_id,
1637 GValue *value,
1638 GParamSpec *pspec)
1639 {
1640 DBusGProxy *proxy = DBUS_G_PROXY (object);
1641 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1642
1643 switch (prop_id)
1644 {
1645 case PROP_NAME:
1646 g_value_set_string (value, priv->name);
1647 break;
1648 case PROP_PATH:
1649 g_value_set_string (value, priv->path);
1650 break;
1651 case PROP_INTERFACE:
1652 g_value_set_string (value, priv->interface);
1653 break;
1654 case PROP_CONNECTION:
1655 g_value_set_boxed (value, DBUS_G_CONNECTION_FROM_CONNECTION(priv->manager->connection));
1656 break;
1657 default:
1658 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1659 break;
1660 }
1661 }
1662
1663 /* this is to avoid people using g_signal_connect() directly,
1664 * to avoid confusion with local signal names, and because
1665 * of the horribly broken current setup (signals are added
1666 * globally to all proxies)
1667 */
1668 static char*
create_signal_name(const char * interface,const char * signal)1669 create_signal_name (const char *interface,
1670 const char *signal)
1671 {
1672 GString *str;
1673 char *p;
1674
1675 str = g_string_new (interface);
1676
1677 g_string_append (str, "-");
1678
1679 g_string_append (str, signal);
1680
1681 /* GLib will silently barf on '.' in signal names */
1682 p = str->str;
1683 while (*p)
1684 {
1685 if (*p == '.')
1686 *p = '-';
1687 ++p;
1688 }
1689
1690 return g_string_free (str, FALSE);
1691 }
1692
1693 static void
marshal_dbus_message_to_g_marshaller(GClosure * closure,GValue * return_value,guint n_param_values,const GValue * param_values,gpointer invocation_hint,gpointer marshal_data)1694 marshal_dbus_message_to_g_marshaller (GClosure *closure,
1695 GValue *return_value,
1696 guint n_param_values,
1697 const GValue *param_values,
1698 gpointer invocation_hint,
1699 gpointer marshal_data)
1700 {
1701 /* Incoming here we have three params, the instance (Proxy), the
1702 * DBusMessage, the signature. We want to convert that to an
1703 * expanded GValue array, then call an appropriate normal GLib
1704 * marshaller.
1705 */
1706 #define MAX_SIGNATURE_ARGS 20
1707 GValueArray *value_array;
1708 DBusGProxy *proxy;
1709 DBusMessage *message;
1710 GArray *gsignature;
1711 const GType *types;
1712 DBusGProxyPrivate *priv;
1713
1714 g_assert (n_param_values == 3);
1715
1716 proxy = g_value_get_object (¶m_values[0]);
1717 message = g_value_get_boxed (¶m_values[1]);
1718 gsignature = g_value_get_pointer (¶m_values[2]);
1719
1720 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
1721 g_return_if_fail (message != NULL);
1722 g_return_if_fail (gsignature != NULL);
1723
1724 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1725
1726 {
1727 DBusGValueMarshalCtx context;
1728 context.recursion_depth = 0;
1729 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
1730 context.proxy = proxy;
1731
1732 types = (const GType*) gsignature->data;
1733 value_array = _dbus_gvalue_demarshal_message (&context, message,
1734 gsignature->len, types, NULL);
1735 }
1736
1737 if (value_array == NULL)
1738 return;
1739
1740 g_value_array_prepend (value_array, NULL);
1741 g_value_init (g_value_array_get_nth (value_array, 0), G_TYPE_FROM_INSTANCE (proxy));
1742 g_value_set_instance (g_value_array_get_nth (value_array, 0), proxy);
1743
1744 g_cclosure_marshal_generic (closure, return_value, value_array->n_values,
1745 value_array->values, invocation_hint, marshal_data);
1746
1747 g_value_array_free (value_array);
1748 }
1749
1750 static void
dbus_g_proxy_emit_remote_signal(DBusGProxy * proxy,DBusMessage * message)1751 dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
1752 DBusMessage *message)
1753 {
1754 const char *interface;
1755 const char *signal;
1756 char *name;
1757 GQuark q;
1758 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
1759 GArray *msg_gsignature = NULL;
1760
1761 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
1762
1763 interface = dbus_message_get_interface (message);
1764 signal = dbus_message_get_member (message);
1765
1766 g_assert (interface != NULL);
1767 g_assert (signal != NULL);
1768
1769 name = create_signal_name (interface, signal);
1770
1771 /* If the quark isn't preexisting, there's no way there
1772 * are any handlers connected. We don't want to create
1773 * extra quarks for every possible signal.
1774 */
1775 q = g_quark_try_string (name);
1776
1777 if (q != 0)
1778 {
1779 GArray *gsignature;
1780 guint i;
1781
1782 gsignature = g_datalist_id_get_data (&priv->signal_signatures, q);
1783 if (gsignature == NULL)
1784 goto out;
1785
1786 msg_gsignature = _dbus_gtypes_from_arg_signature (dbus_message_get_signature (message),
1787 TRUE);
1788 for (i = 0; i < gsignature->len; i++)
1789 {
1790 if (msg_gsignature->len == i
1791 || g_array_index (gsignature, GType, i) != g_array_index (msg_gsignature, GType, i))
1792 goto mismatch;
1793 }
1794 if (msg_gsignature->len != i)
1795 goto mismatch;
1796
1797 g_signal_emit (proxy,
1798 signals[RECEIVED],
1799 q,
1800 message,
1801 msg_gsignature);
1802 }
1803
1804 out:
1805 g_free (name);
1806 if (msg_gsignature)
1807 g_array_free (msg_gsignature, TRUE);
1808 return;
1809 mismatch:
1810 #if 0
1811 /* Don't spew on remote errors */
1812 g_warning ("Unexpected message signature '%s' for signal '%s'\n",
1813 dbus_message_get_signature (message),
1814 name);
1815 #endif
1816 goto out;
1817 }
1818
1819 /**
1820 * DBusGProxyCallNotify:
1821 * @proxy: the proxy on which the method was called
1822 * @call_id: the call in progress
1823 * @user_data: data passed to dbus_g_proxy_begin_call() or similar
1824 *
1825 * Called when a reply to the call represented by @call_id arrives.
1826 * Use dbus_g_proxy_end_call() to see whether @call_id succeeded or
1827 * failed, and get the arguments returned (if any) on success.
1828 *
1829 * Deprecated: New code should use GDBus instead. The closest equivalent
1830 * is the standard #GAsyncReadyCallback mechanism.
1831 */
1832
1833 typedef struct
1834 {
1835 DBusGProxy *proxy;
1836 guint call_id;
1837 DBusGProxyCallNotify func;
1838 void *data;
1839 GDestroyNotify free_data_func;
1840 } GPendingNotifyClosure;
1841
1842 static void
d_pending_call_notify(DBusPendingCall * dcall,void * data)1843 d_pending_call_notify (DBusPendingCall *dcall,
1844 void *data)
1845 {
1846 GPendingNotifyClosure *closure = data;
1847
1848 (* closure->func) (closure->proxy, DBUS_G_PROXY_ID_TO_CALL (closure->call_id), closure->data);
1849 }
1850
1851 static void
d_pending_call_free(void * data)1852 d_pending_call_free (void *data)
1853 {
1854 GPendingNotifyClosure *closure = data;
1855
1856 if (closure->free_data_func)
1857 (* closure->free_data_func) (closure->data);
1858
1859 g_free (closure);
1860 }
1861
1862 #define DBUS_G_VALUE_ARRAY_COLLECT_ALL(VALARRAY, FIRST_ARG_TYPE, ARGS) \
1863 G_STMT_START { \
1864 GType valtype; \
1865 guint i = 0; \
1866 \
1867 VALARRAY = g_value_array_new (6); \
1868 valtype = FIRST_ARG_TYPE; \
1869 \
1870 while (valtype != G_TYPE_INVALID) \
1871 { \
1872 gchar *collect_err; \
1873 GValue *val; \
1874 \
1875 g_value_array_append (VALARRAY, NULL); \
1876 val = g_value_array_get_nth (VALARRAY, i); \
1877 g_value_init (val, valtype); \
1878 collect_err = NULL; \
1879 G_VALUE_COLLECT (val, ARGS, G_VALUE_NOCOPY_CONTENTS, &collect_err); \
1880 \
1881 if (collect_err) \
1882 { \
1883 g_critical ("%s: unable to collect argument %u: %s", \
1884 G_STRFUNC, i, collect_err); \
1885 g_free (collect_err); \
1886 g_value_array_free (VALARRAY); \
1887 VALARRAY = NULL; \
1888 break; \
1889 } \
1890 \
1891 valtype = va_arg (ARGS, GType); \
1892 i++; \
1893 } \
1894 } G_STMT_END
1895
1896 DBusGProxyCall *
manager_begin_bus_call(DBusGProxyManager * manager,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GType first_arg_type,...)1897 manager_begin_bus_call (DBusGProxyManager *manager,
1898 const char *method,
1899 DBusGProxyCallNotify notify,
1900 gpointer user_data,
1901 GDestroyNotify destroy,
1902 GType first_arg_type,
1903 ...)
1904 {
1905 guint call_id = 0;
1906 DBusGProxyPrivate *priv;
1907 va_list args;
1908 GValueArray *arg_values;
1909
1910 va_start (args, first_arg_type);
1911
1912 if (!manager->bus_proxy)
1913 {
1914 manager->bus_proxy = g_object_new (DBUS_TYPE_G_PROXY,
1915 "name", DBUS_SERVICE_DBUS,
1916 "path", DBUS_PATH_DBUS,
1917 "interface", DBUS_INTERFACE_DBUS,
1918 NULL);
1919 priv = DBUS_G_PROXY_GET_PRIVATE(manager->bus_proxy);
1920 priv->manager = manager;
1921 }
1922
1923 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
1924
1925 if (arg_values != NULL)
1926 {
1927 call_id = dbus_g_proxy_begin_call_internal (manager->bus_proxy, method,
1928 notify, user_data, destroy, arg_values, -1);
1929
1930 g_value_array_free (arg_values);
1931 }
1932
1933 va_end (args);
1934
1935 return DBUS_G_PROXY_ID_TO_CALL (call_id);
1936 }
1937
1938 /**
1939 * SECTION:dbus-gproxy
1940 * @title: DBusGProxy
1941 * @short_description: DBus Proxy
1942 * @see_also: #DBusGProxy
1943 * @stability: Stable
1944 *
1945 * A #DBusGProxy is a #GObject representing a remote object in a D-Bus
1946 * service.
1947 *
1948 * Deprecated: New code should use #GDBusProxy instead.
1949 */
1950
1951 /**
1952 * DBusGProxy:
1953 *
1954 * A #GObject representing a remote object in a D-Bus service.
1955 *
1956 * Deprecated: New code should use GDBus instead. The closest equivalent
1957 * is #GDBusProxy.
1958 */
1959
1960 /**
1961 * DBusGProxyCall:
1962 *
1963 * An opaque pointer representing an asynchronous call in progress.
1964 *
1965 * Deprecated: New code should use GDBus instead. There is no direct
1966 * equivalent in GDBus, but the standard #GCancellable mechanism is
1967 * analogous.
1968 */
1969
1970 /*
1971 * dbus_g_proxy_get_type:
1972 * Standard GObject get_type() function for DBusGProxy.
1973 *
1974 * Returns: type ID for DBusGProxy class
1975 *
1976 * Deprecated: New code should use #GDBusProxy instead.
1977 */
1978 GType
dbus_g_proxy_get_type(void)1979 dbus_g_proxy_get_type (void)
1980 {
1981 static GType object_type = 0;
1982
1983 if (!object_type)
1984 {
1985 static const GTypeInfo object_info =
1986 {
1987 sizeof (DBusGProxyClass),
1988 (GBaseInitFunc) NULL,
1989 (GBaseFinalizeFunc) NULL,
1990 (GClassInitFunc) dbus_g_proxy_class_init,
1991 NULL, /* class_finalize */
1992 NULL, /* class_data */
1993 sizeof (DBusGProxy),
1994 0, /* n_preallocs */
1995 (GInstanceInitFunc) dbus_g_proxy_init,
1996 };
1997
1998 object_type = g_type_register_static (G_TYPE_OBJECT,
1999 "DBusGProxy",
2000 &object_info, 0);
2001 }
2002
2003 return object_type;
2004 }
2005
2006 static DBusGProxy*
dbus_g_proxy_new(DBusGConnection * connection,const char * name,const char * path_name,const char * interface_name)2007 dbus_g_proxy_new (DBusGConnection *connection,
2008 const char *name,
2009 const char *path_name,
2010 const char *interface_name)
2011 {
2012 DBusGProxy *proxy;
2013
2014 g_assert (connection != NULL);
2015
2016 proxy = g_object_new (DBUS_TYPE_G_PROXY,
2017 "name", name,
2018 "path", path_name,
2019 "interface", interface_name,
2020 "connection", connection, NULL);
2021
2022 return proxy;
2023 }
2024
2025 /**
2026 * dbus_g_proxy_new_for_name:
2027 * @connection: the connection to the remote bus
2028 * @name: any name on the message bus
2029 * @path: name of the object instance to call methods on
2030 * @iface: name of the interface to call methods on
2031 *
2032 * Creates a new proxy for a remote interface exported by a connection
2033 * on a message bus. Method calls and signal connections over this
2034 * proxy will go to the name owner; the name's owner is expected to
2035 * support the given interface name. THE NAME OWNER MAY CHANGE OVER
2036 * TIME, for example between two different method calls, unless the
2037 * name is a unique name. If you need a fixed owner, you need to
2038 * request the current owner and bind a proxy to its unique name
2039 * rather than to the generic name; see
2040 * dbus_g_proxy_new_for_name_owner().
2041 *
2042 * A name-associated proxy only makes sense with a message bus, not
2043 * for app-to-app direct dbus connections.
2044 *
2045 * This proxy will only emit the "destroy" signal if the
2046 * #DBusConnection is disconnected, the proxy has no remaining
2047 * references, or the name is a unique name and its owner
2048 * disappears. If a well-known name changes owner, the proxy will
2049 * still be alive.
2050 *
2051 * Returns: new proxy object
2052 *
2053 * Deprecated: New code should use GDBus instead. The closest equivalent
2054 * is g_dbus_proxy_new_sync().
2055 */
2056 DBusGProxy*
dbus_g_proxy_new_for_name(DBusGConnection * connection,const char * name,const char * path,const char * iface)2057 dbus_g_proxy_new_for_name (DBusGConnection *connection,
2058 const char *name,
2059 const char *path,
2060 const char *iface)
2061 {
2062 g_return_val_if_fail (connection != NULL, NULL);
2063 g_return_val_if_fail (g_dbus_is_name (name), NULL);
2064 g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2065 g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2066
2067 return dbus_g_proxy_new (connection, name, path, iface);
2068 }
2069
2070 /**
2071 * dbus_g_proxy_new_for_name_owner:
2072 * @connection: the connection to the remote bus
2073 * @name: any name on the message bus
2074 * @path: name of the object inside the service to call methods on
2075 * @iface: name of the interface to call methods on
2076 * @error: return location for an error
2077 *
2078 * Similar to dbus_g_proxy_new_for_name(), but makes a round-trip
2079 * request to the message bus to get the current name owner, then
2080 * binds the proxy to the unique name of the current owner, rather
2081 * than to the well-known name. As a result, the name owner will
2082 * not change over time, and the proxy will emit the "destroy" signal
2083 * when the owner disappears from the message bus.
2084 *
2085 * An example of the difference between dbus_g_proxy_new_for_name()
2086 * and dbus_g_proxy_new_for_name_owner(): if you provide the well-known name
2087 * "org.freedesktop.Database" dbus_g_proxy_new_for_name() remains bound
2088 * to that name as it changes owner. dbus_g_proxy_new_for_name_owner()
2089 * will fail if the name has no owner. If the name has an owner,
2090 * dbus_g_proxy_new_for_name_owner() will bind to the unique name
2091 * of that owner rather than the generic name.
2092 *
2093 * Returns: new proxy object, or %NULL on error
2094 *
2095 * Deprecated: New code should use GDBus instead. The closest equivalent
2096 * is g_dbus_proxy_new_sync() with the name owner's unique name
2097 * passed as @name.
2098 */
2099 DBusGProxy*
dbus_g_proxy_new_for_name_owner(DBusGConnection * connection,const char * name,const char * path,const char * iface,GError ** error)2100 dbus_g_proxy_new_for_name_owner (DBusGConnection *connection,
2101 const char *name,
2102 const char *path,
2103 const char *iface,
2104 GError **error)
2105 {
2106 DBusGProxy *proxy;
2107 char *unique_name;
2108
2109 g_return_val_if_fail (connection != NULL, NULL);
2110 g_return_val_if_fail (g_dbus_is_name (name), NULL);
2111 g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2112 g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2113
2114 if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error)))
2115 return NULL;
2116
2117 proxy = dbus_g_proxy_new (connection, unique_name, path, iface);
2118 g_free (unique_name);
2119 return proxy;
2120 }
2121
2122 /**
2123 * dbus_g_proxy_new_from_proxy:
2124 * @proxy: the proxy to use as a template
2125 * @iface: name of the interface to call methods on
2126 * @path: of the object inside the peer to call methods on
2127 *
2128 * Creates a proxy using an existing proxy as a template, substituting
2129 * the specified interface and path. Either or both may be NULL.
2130 *
2131 * Returns: new proxy object
2132 *
2133 * Deprecated: New code should use GDBus instead. The closest equivalent
2134 * is g_dbus_proxy_new_sync().
2135 */
2136 DBusGProxy*
dbus_g_proxy_new_from_proxy(DBusGProxy * proxy,const char * iface,const char * path)2137 dbus_g_proxy_new_from_proxy (DBusGProxy *proxy,
2138 const char *iface,
2139 const char *path)
2140 {
2141 DBusGProxyPrivate *priv;
2142
2143 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2144 g_return_val_if_fail (path == NULL || g_variant_is_object_path (path), NULL);
2145 g_return_val_if_fail (iface == NULL ||
2146 g_dbus_is_interface_name (iface), NULL);
2147
2148 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2149
2150 if (iface == NULL)
2151 iface = priv->interface;
2152 if (path == NULL)
2153 path = priv->path;
2154
2155 return dbus_g_proxy_new (DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection),
2156 priv->name,
2157 path, iface);
2158 }
2159
2160 /**
2161 * dbus_g_proxy_new_for_peer:
2162 * @connection: the connection to the peer
2163 * @path: name of the object inside the peer to call methods on
2164 * @iface: name of the interface to call methods on
2165 *
2166 * Creates a proxy for an object in peer application (one
2167 * we're directly connected to). That is, this function is
2168 * intended for use when there's no message bus involved,
2169 * we're doing a simple 1-to-1 communication between two
2170 * applications.
2171 *
2172 * Returns: new proxy object
2173 *
2174 * Deprecated: New code should use GDBus instead. The closest equivalent
2175 * is g_dbus_proxy_new_sync().
2176 */
2177 DBusGProxy*
dbus_g_proxy_new_for_peer(DBusGConnection * connection,const char * path,const char * iface)2178 dbus_g_proxy_new_for_peer (DBusGConnection *connection,
2179 const char *path,
2180 const char *iface)
2181 {
2182 DBusGProxy *proxy;
2183
2184 g_return_val_if_fail (connection != NULL, NULL);
2185 g_return_val_if_fail (g_variant_is_object_path (path), NULL);
2186 g_return_val_if_fail (g_dbus_is_interface_name (iface), NULL);
2187
2188 proxy = dbus_g_proxy_new (connection, NULL, path, iface);
2189
2190 return proxy;
2191 }
2192
2193 /**
2194 * dbus_g_proxy_get_bus_name:
2195 * @proxy: the proxy
2196 *
2197 * Gets the bus name a proxy is bound to (may be %NULL in some cases).
2198 * If you created the proxy with dbus_g_proxy_new_for_name(), then
2199 * the name you passed to that will be returned.
2200 * If you created it with dbus_g_proxy_new_for_name_owner(), then the
2201 * unique connection name will be returned. If you created it
2202 * with dbus_g_proxy_new_for_peer() then %NULL will be returned.
2203 *
2204 * It is an error to call this method on a proxy that has emitted
2205 * the #DBusGProxy::destroy signal.
2206 *
2207 * Returns: the bus name the proxy sends messages to
2208 *
2209 * Deprecated: New code should use GDBus instead. The closest equivalent
2210 * is g_dbus_proxy_get_name() or g_dbus_proxy_get_name_owner(),
2211 * depending how the proxy was created.
2212 */
2213 const char*
dbus_g_proxy_get_bus_name(DBusGProxy * proxy)2214 dbus_g_proxy_get_bus_name (DBusGProxy *proxy)
2215 {
2216 DBusGProxyPrivate *priv;
2217
2218 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2219 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2220
2221 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2222
2223 return priv->name;
2224 }
2225
2226 /**
2227 * dbus_g_proxy_get_interface:
2228 * @proxy: the proxy
2229 *
2230 * Gets the object interface proxy is bound to (may be %NULL in some cases).
2231 *
2232 * It is an error to call this method on a proxy that has emitted
2233 * the #DBusGProxy::destroy signal.
2234 *
2235 * Returns: an object interface
2236 *
2237 * Deprecated: New code should use GDBus instead. The closest equivalent
2238 * is g_dbus_proxy_get_interface_name().
2239 */
2240 const char*
dbus_g_proxy_get_interface(DBusGProxy * proxy)2241 dbus_g_proxy_get_interface (DBusGProxy *proxy)
2242 {
2243 DBusGProxyPrivate *priv;
2244
2245 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2246 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2247
2248 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2249
2250 return priv->interface;
2251 }
2252
2253 /**
2254 * dbus_g_proxy_set_interface:
2255 * @proxy: the proxy
2256 * @interface_name: an object interface
2257 *
2258 * Sets the object interface proxy is bound to
2259 *
2260 * It is an error to call this method on a proxy that has emitted
2261 * the #DBusGProxy::destroy signal.
2262 *
2263 * Deprecated: New code should use GDBus instead. There is no
2264 * direct equivalent for this function: construct a new proxy instead.
2265 */
2266 void
dbus_g_proxy_set_interface(DBusGProxy * proxy,const char * interface_name)2267 dbus_g_proxy_set_interface (DBusGProxy *proxy,
2268 const char *interface_name)
2269 {
2270 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2271
2272 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2273 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2274 g_return_if_fail (g_dbus_is_interface_name (interface_name));
2275
2276 /* FIXME - need to unregister when we switch interface for now
2277 * later should support idea of unset interface
2278 */
2279 dbus_g_proxy_manager_unregister (priv->manager, proxy);
2280 g_free (priv->interface);
2281 priv->interface = g_strdup (interface_name);
2282 dbus_g_proxy_manager_register (priv->manager, proxy);
2283 }
2284
2285 /**
2286 * dbus_g_proxy_get_path:
2287 * @proxy: the proxy
2288 *
2289 * Gets the path this proxy is bound to
2290 *
2291 * It is an error to call this method on a proxy that has emitted
2292 * the #DBusGProxy::destroy signal.
2293 *
2294 * Returns: an object path
2295 *
2296 * Deprecated: New code should use GDBus instead. The closest equivalent
2297 * is g_dbus_proxy_get_object_path().
2298 */
2299 const char*
dbus_g_proxy_get_path(DBusGProxy * proxy)2300 dbus_g_proxy_get_path (DBusGProxy *proxy)
2301 {
2302 DBusGProxyPrivate *priv;
2303
2304 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2305 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2306
2307 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2308
2309 return priv->path;
2310 }
2311
2312 static DBusMessage *
dbus_g_proxy_marshal_args_to_message(DBusGProxy * proxy,const char * method,GValueArray * args)2313 dbus_g_proxy_marshal_args_to_message (DBusGProxy *proxy,
2314 const char *method,
2315 GValueArray *args)
2316 {
2317 DBusMessage *message;
2318 DBusMessageIter msgiter;
2319 guint i;
2320 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2321
2322 message = dbus_message_new_method_call (priv->name,
2323 priv->path,
2324 priv->interface,
2325 method);
2326 if (message == NULL)
2327 return NULL;
2328
2329 dbus_message_iter_init_append (message, &msgiter);
2330 for (i = 0; i < args->n_values; i++)
2331 {
2332 GValue *gvalue;
2333
2334 gvalue = g_value_array_get_nth (args, i);
2335
2336 if (!_dbus_gvalue_marshal (&msgiter, gvalue))
2337 {
2338 /* This is a programming error by the caller, most likely */
2339 gchar *contents = g_strdup_value_contents (gvalue);
2340
2341 g_critical ("Could not marshal argument %u for %s: type %s, value %s",
2342 i, method, G_VALUE_TYPE_NAME (gvalue), contents);
2343 g_free (contents);
2344 dbus_message_unref (message);
2345 return NULL;
2346 }
2347 }
2348
2349 return message;
2350 }
2351
2352 static guint
dbus_g_proxy_begin_call_internal(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GValueArray * args,int timeout)2353 dbus_g_proxy_begin_call_internal (DBusGProxy *proxy,
2354 const char *method,
2355 DBusGProxyCallNotify notify,
2356 gpointer user_data,
2357 GDestroyNotify destroy,
2358 GValueArray *args,
2359 int timeout)
2360 {
2361 DBusMessage *message;
2362 DBusPendingCall *pending;
2363 GPendingNotifyClosure *closure;
2364 guint call_id;
2365 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2366
2367 pending = NULL;
2368
2369 message = dbus_g_proxy_marshal_args_to_message (proxy, method, args);
2370
2371 /* can only happen on a programming error or OOM; we already critical'd */
2372 if (!message)
2373 return 0;
2374
2375 if (!dbus_connection_send_with_reply (priv->manager->connection,
2376 message,
2377 &pending,
2378 timeout))
2379 oom ();
2380
2381 dbus_message_unref (message);
2382
2383 /* If we got a NULL pending, that means the connection was disconnected,
2384 * and we need to abort this call.
2385 * https://bugs.freedesktop.org/show_bug.cgi?id=12675
2386 */
2387 if (pending == NULL)
2388 return 0;
2389
2390 call_id = ++priv->call_id_counter;
2391
2392 if (notify != NULL)
2393 {
2394 closure = g_new (GPendingNotifyClosure, 1);
2395 closure->proxy = proxy; /* No need to ref as the lifecycle is tied to proxy */
2396 closure->call_id = call_id;
2397 closure->func = notify;
2398 closure->data = user_data;
2399 closure->free_data_func = destroy;
2400 dbus_pending_call_set_notify (pending, d_pending_call_notify,
2401 closure,
2402 d_pending_call_free);
2403 }
2404
2405 g_hash_table_insert (priv->pending_calls, GUINT_TO_POINTER (call_id), pending);
2406
2407 return call_id;
2408 }
2409
2410 static gboolean
dbus_g_proxy_end_call_internal(DBusGProxy * proxy,guint call_id,GError ** error,GType first_arg_type,va_list args)2411 dbus_g_proxy_end_call_internal (DBusGProxy *proxy,
2412 guint call_id,
2413 GError **error,
2414 GType first_arg_type,
2415 va_list args)
2416 {
2417 DBusMessage *reply;
2418 DBusMessageIter msgiter;
2419 DBusError derror;
2420 va_list args_unwind;
2421 guint over;
2422 int n_retvals_processed;
2423 gboolean ret;
2424 GType valtype;
2425 DBusPendingCall *pending;
2426 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2427
2428 if (call_id == 0)
2429 {
2430 /* Being disconnected is the only reason this can happen, except
2431 * for programmer error; if it was programmer error, we already
2432 * emitted a critical warning. */
2433 g_set_error (error, DBUS_GERROR, DBUS_GERROR_DISCONNECTED,
2434 "Disconnected from D-Bus (or argument error during call)");
2435 return FALSE;
2436 }
2437
2438 reply = NULL;
2439 ret = FALSE;
2440 n_retvals_processed = 0;
2441 over = 0;
2442
2443 /* Keep around a copy of output arguments so we can free on error. */
2444 G_VA_COPY(args_unwind, args);
2445
2446 pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2447
2448 dbus_pending_call_block (pending);
2449 reply = dbus_pending_call_steal_reply (pending);
2450
2451 g_assert (reply != NULL);
2452
2453 dbus_error_init (&derror);
2454
2455 switch (dbus_message_get_type (reply))
2456 {
2457 case DBUS_MESSAGE_TYPE_METHOD_RETURN:
2458 dbus_message_iter_init (reply, &msgiter);
2459 valtype = first_arg_type;
2460 while (valtype != G_TYPE_INVALID)
2461 {
2462 int arg_type;
2463 gpointer return_storage;
2464 GValue gvalue = { 0, };
2465 DBusGValueMarshalCtx context;
2466
2467 context.recursion_depth = 0;
2468 context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (priv->manager->connection);
2469 context.proxy = proxy;
2470
2471 arg_type = dbus_message_iter_get_arg_type (&msgiter);
2472 if (arg_type == DBUS_TYPE_INVALID)
2473 {
2474 g_set_error (error, DBUS_GERROR,
2475 DBUS_GERROR_INVALID_ARGS,
2476 "Too few arguments in reply");
2477 goto out;
2478 }
2479
2480 return_storage = va_arg (args, gpointer);
2481 if (return_storage == NULL)
2482 goto next;
2483
2484 /* We handle variants specially; the caller is expected
2485 * to have already allocated storage for them.
2486 */
2487 if (arg_type == DBUS_TYPE_VARIANT
2488 && g_type_is_a (valtype, G_TYPE_VALUE))
2489 {
2490 if (!_dbus_gvalue_demarshal_variant (&context, &msgiter, (GValue*) return_storage, NULL))
2491 {
2492 g_set_error (error,
2493 DBUS_GERROR,
2494 DBUS_GERROR_INVALID_ARGS,
2495 "Couldn't convert argument, expected \"%s\"",
2496 g_type_name (valtype));
2497 goto out;
2498 }
2499 }
2500 else
2501 {
2502 g_value_init (&gvalue, valtype);
2503
2504 if (!_dbus_gvalue_demarshal (&context, &msgiter, &gvalue, error))
2505 goto out;
2506
2507 /* Anything that can be demarshaled must be storable */
2508 if (!_dbus_gvalue_store (&gvalue, return_storage))
2509 g_assert_not_reached ();
2510 /* Ownership of the value passes to the client, don't unset */
2511 }
2512
2513 next:
2514 n_retvals_processed++;
2515 dbus_message_iter_next (&msgiter);
2516 valtype = va_arg (args, GType);
2517 }
2518
2519 while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
2520 {
2521 over++;
2522 dbus_message_iter_next (&msgiter);
2523 }
2524
2525 if (over > 0)
2526 {
2527 g_set_error (error, DBUS_GERROR,
2528 DBUS_GERROR_INVALID_ARGS,
2529 "Too many arguments in reply; expected %d, got %d",
2530 n_retvals_processed, over);
2531 goto out;
2532 }
2533 break;
2534 case DBUS_MESSAGE_TYPE_ERROR:
2535 dbus_set_error_from_message (&derror, reply);
2536 dbus_set_g_error (error, &derror);
2537 dbus_error_free (&derror);
2538 goto out;
2539 break;
2540 default:
2541 dbus_set_error (&derror, DBUS_ERROR_FAILED,
2542 "Reply was neither a method return nor an exception");
2543 dbus_set_g_error (error, &derror);
2544 dbus_error_free (&derror);
2545 goto out;
2546 break;
2547 }
2548
2549 ret = TRUE;
2550 out:
2551 if (ret == FALSE)
2552 {
2553 int i;
2554
2555 valtype = first_arg_type;
2556 for (i = 0; i < n_retvals_processed; i++)
2557 {
2558 GValue value = {0,};
2559 gpointer retval;
2560
2561 g_value_init (&value, valtype);
2562
2563 retval = va_arg (args_unwind, gpointer);
2564 if (retval == NULL)
2565 {
2566 i--;
2567 continue;
2568 }
2569
2570 _dbus_gvalue_take (&value, retval);
2571 g_value_unset (&value);
2572
2573 valtype = va_arg (args_unwind, GType);
2574 }
2575 }
2576 va_end (args_unwind);
2577 va_end (args);
2578
2579 g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2580
2581 if (reply)
2582 dbus_message_unref (reply);
2583 return ret;
2584 }
2585
2586 /**
2587 * dbus_g_proxy_begin_call:
2588 * @proxy: a proxy for a remote interface
2589 * @method: the name of the method to invoke
2590 * @notify: callback to be invoked when method returns
2591 * @user_data: user data passed to callback
2592 * @destroy: function called to destroy user_data
2593 * @first_arg_type: type of the first argument, or %G_TYPE_INVALID if there
2594 * are no arguments
2595 * @...: first argument, followed by any further type/value pairs, followed
2596 * by %G_TYPE_INVALID
2597 *
2598 * Asynchronously invokes a method on a remote interface. The method
2599 * call will not be sent over the wire until the application returns
2600 * to the main loop, or blocks in dbus_g_connection_flush() to write out
2601 * pending data. The call will be completed after a timeout, or when
2602 * a reply is received. When the call returns, the callback specified
2603 * will be invoked; you can then collect the results of the call
2604 * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2605 *
2606 * It is an error to call this method on a proxy that has emitted
2607 * the #DBusGProxy::destroy signal.
2608 *
2609 * TODO this particular function shouldn't die on out of memory,
2610 * since you should be able to do a call with large arguments.
2611 *
2612 * Returns: call identifier.
2613 *
2614 * Deprecated: New code should use GDBus instead. The closest equivalent
2615 * is g_dbus_proxy_call().
2616 */
2617 DBusGProxyCall *
dbus_g_proxy_begin_call(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,GType first_arg_type,...)2618 dbus_g_proxy_begin_call (DBusGProxy *proxy,
2619 const char *method,
2620 DBusGProxyCallNotify notify,
2621 gpointer user_data,
2622 GDestroyNotify destroy,
2623 GType first_arg_type,
2624 ...)
2625 {
2626 guint call_id = 0;
2627 va_list args;
2628 GValueArray *arg_values;
2629 DBusGProxyPrivate *priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2630
2631 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2632 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2633 g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
2634
2635 va_start (args, first_arg_type);
2636
2637 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2638
2639 if (arg_values != NULL)
2640 {
2641 call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify,
2642 user_data, destroy, arg_values, priv->default_timeout);
2643
2644 g_value_array_free (arg_values);
2645 }
2646
2647 va_end (args);
2648
2649 return DBUS_G_PROXY_ID_TO_CALL (call_id);
2650 }
2651
2652 /**
2653 * dbus_g_proxy_begin_call_with_timeout:
2654 * @proxy: a proxy for a remote interface
2655 * @method: the name of the method to invoke
2656 * @notify: callback to be invoked when method returns
2657 * @user_data: user data passed to callback
2658 * @destroy: function called to destroy user_data
2659 * @timeout: the timeout in milliseconds, or -1 to use a default
2660 * @first_arg_type: type of the first argument, or %G_TYPE_INVALID if there
2661 * are no arguments
2662 * @...: first argument, followed by any further type/value pairs, followed
2663 * by %G_TYPE_INVALID
2664 *
2665 * Asynchronously invokes a method on a remote interface. The method
2666 * call will not be sent over the wire until the application returns
2667 * to the main loop, or blocks in dbus_g_connection_flush() to write out
2668 * pending data. The call will be completed after a timeout, or when
2669 * a reply is received. When the call returns, the callback specified
2670 * will be invoked; you can then collect the results of the call
2671 * (which may be an error, or a reply), use dbus_g_proxy_end_call().
2672 *
2673 * It is an error to call this method on a proxy that has emitted
2674 * the #DBusGProxy::destroy signal.
2675 *
2676 * TODO this particular function shouldn't die on out of memory,
2677 * since you should be able to do a call with large arguments.
2678 *
2679 * Returns: call identifier.
2680 *
2681 * Deprecated: New code should use GDBus instead. The closest equivalent
2682 * is g_dbus_proxy_call().
2683 */
2684 DBusGProxyCall *
dbus_g_proxy_begin_call_with_timeout(DBusGProxy * proxy,const char * method,DBusGProxyCallNotify notify,gpointer user_data,GDestroyNotify destroy,int timeout,GType first_arg_type,...)2685 dbus_g_proxy_begin_call_with_timeout (DBusGProxy *proxy,
2686 const char *method,
2687 DBusGProxyCallNotify notify,
2688 gpointer user_data,
2689 GDestroyNotify destroy,
2690 int timeout,
2691 GType first_arg_type,
2692 ...)
2693 {
2694 guint call_id = 0;
2695 va_list args;
2696 GValueArray *arg_values;
2697
2698 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), NULL);
2699 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), NULL);
2700 g_return_val_if_fail (g_dbus_is_member_name (method), NULL);
2701 g_return_val_if_fail (timeout >= 0 || timeout == -1, NULL);
2702
2703 va_start (args, first_arg_type);
2704
2705 DBUS_G_VALUE_ARRAY_COLLECT_ALL (arg_values, first_arg_type, args);
2706
2707 if (arg_values != NULL)
2708 {
2709 call_id = dbus_g_proxy_begin_call_internal (proxy, method, notify,
2710 user_data, destroy, arg_values, timeout);
2711
2712 g_value_array_free (arg_values);
2713 }
2714
2715 va_end (args);
2716
2717 return DBUS_G_PROXY_ID_TO_CALL (call_id);
2718 }
2719
2720 /**
2721 * dbus_g_proxy_end_call:
2722 * @proxy: a proxy for a remote interface
2723 * @call: the pending call ID from dbus_g_proxy_begin_call()
2724 * @error: return location for an error
2725 * @first_arg_type: type of first "out" argument, or %G_TYPE_INVALID if
2726 * there are no "out" arguments
2727 * @...: return location for first "out" argument, followed by any further
2728 * type/location pairs, followed by %G_TYPE_INVALID
2729 *
2730 * Collects the results of a method call. The method call was normally
2731 * initiated with dbus_g_proxy_end_call(). You may use this function
2732 * outside of the callback given to dbus_g_proxy_begin_call; in that
2733 * case this function will block if the results haven't yet been
2734 * received.
2735 *
2736 * All D-Bus method calls can fail with a remote error. If this occurs,
2737 * the @error will be set and this function will return %FALSE.
2738 *
2739 * Otherwise, the "out" parameters and return value of the
2740 * method are stored in the provided varargs list.
2741 * The list should be terminated with G_TYPE_INVALID.
2742 *
2743 * Returns: %TRUE on success
2744 *
2745 * Deprecated: New code should use GDBus instead. The closest equivalent
2746 * is g_dbus_proxy_call_finish().
2747 */
2748 gboolean
dbus_g_proxy_end_call(DBusGProxy * proxy,DBusGProxyCall * call,GError ** error,GType first_arg_type,...)2749 dbus_g_proxy_end_call (DBusGProxy *proxy,
2750 DBusGProxyCall *call,
2751 GError **error,
2752 GType first_arg_type,
2753 ...)
2754 {
2755 gboolean ret;
2756 va_list args;
2757
2758 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2759
2760 va_start (args, first_arg_type);
2761
2762 ret = dbus_g_proxy_end_call_internal (proxy, GPOINTER_TO_UINT (call), error, first_arg_type, args);
2763
2764 va_end (args);
2765
2766 return ret;
2767 }
2768
2769 /**
2770 * dbus_g_proxy_call:
2771 * @proxy: a proxy for a remote interface
2772 * @method: method to invoke
2773 * @error: return location for an error
2774 * @first_arg_type: type of first "in" argument, or %G_TYPE_INVALID if none
2775 * @...: value of first "in" argument, any further type/value pairs,
2776 * %G_TYPE_INVALID, type/location pairs for "out" arguments,
2777 * and %G_TYPE_INVALID again
2778 *
2779 * Function for synchronously invoking a method and receiving reply
2780 * values. This function is equivalent to dbus_g_proxy_begin_call
2781 * followed by dbus_g_proxy_end_call. All of the input arguments are
2782 * specified first, followed by G_TYPE_INVALID, followed by all of the
2783 * output values, followed by a second G_TYPE_INVALID. Note that
2784 * this means you must always specify G_TYPE_INVALID twice.
2785 *
2786 * It is an error to call this method on a proxy that has emitted
2787 * the #DBusGProxy::destroy signal.
2788 *
2789 * Returns: %TRUE if the method succeeds, %FALSE if it fails
2790 *
2791 * Deprecated: New code should use GDBus instead. The closest equivalent
2792 * is g_dbus_proxy_call_sync().
2793 */
2794 gboolean
dbus_g_proxy_call(DBusGProxy * proxy,const char * method,GError ** error,GType first_arg_type,...)2795 dbus_g_proxy_call (DBusGProxy *proxy,
2796 const char *method,
2797 GError **error,
2798 GType first_arg_type,
2799 ...)
2800 {
2801 gboolean ret;
2802 guint call_id = 0;
2803 va_list args;
2804 GValueArray *in_args;
2805 DBusGProxyPrivate *priv;
2806
2807 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2808 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2809
2810 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2811
2812 va_start (args, first_arg_type);
2813
2814 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2815
2816 if (in_args != NULL)
2817 {
2818 call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL,
2819 NULL, in_args, priv->default_timeout);
2820
2821 g_value_array_free (in_args);
2822 }
2823
2824 first_arg_type = va_arg (args, GType);
2825 ret = dbus_g_proxy_end_call_internal (proxy, call_id, error, first_arg_type,
2826 args);
2827
2828 va_end (args);
2829
2830 return ret;
2831 }
2832
2833 /**
2834 * dbus_g_proxy_call_with_timeout:
2835 * @proxy: a proxy for a remote interface
2836 * @method: method to invoke
2837 * @timeout: the timeout in milliseconds, or -1 to use a default
2838 * @error: return location for an error
2839 * @first_arg_type: type of first "in" argument
2840 * @...: as for dbus_g_proxy_call()
2841 *
2842 * Function for synchronously invoking a method and receiving reply
2843 * values. This function is equivalent to dbus_g_proxy_begin_call
2844 * followed by dbus_g_proxy_end_call. All of the input arguments are
2845 * specified first, followed by G_TYPE_INVALID, followed by all of the
2846 * output values, followed by a second G_TYPE_INVALID. Note that
2847 * this means you must always specify G_TYPE_INVALID twice.
2848 *
2849 * It is an error to call this method on a proxy that has emitted
2850 * the #DBusGProxy::destroy signal.
2851 *
2852 * Returns: %TRUE if the method succeeds, %FALSE if it fails
2853 *
2854 * Deprecated: New code should use GDBus instead. The closest equivalent
2855 * is g_dbus_proxy_call_sync().
2856 */
2857 gboolean
dbus_g_proxy_call_with_timeout(DBusGProxy * proxy,const char * method,int timeout,GError ** error,GType first_arg_type,...)2858 dbus_g_proxy_call_with_timeout (DBusGProxy *proxy,
2859 const char *method,
2860 int timeout,
2861 GError **error,
2862 GType first_arg_type,
2863 ...)
2864 {
2865 gboolean ret;
2866 guint call_id = 0;
2867 va_list args;
2868 GValueArray *in_args;
2869
2870 g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
2871 g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
2872 g_return_val_if_fail (g_dbus_is_member_name (method), FALSE);
2873 g_return_val_if_fail (timeout >= 0 || timeout == -1, FALSE);
2874
2875 va_start (args, first_arg_type);
2876
2877 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2878
2879 if (in_args != NULL)
2880 {
2881 call_id = dbus_g_proxy_begin_call_internal (proxy, method, NULL, NULL,
2882 NULL, in_args, timeout);
2883
2884 g_value_array_free (in_args);
2885 }
2886
2887 first_arg_type = va_arg (args, GType);
2888 ret = dbus_g_proxy_end_call_internal (proxy, call_id, error,
2889 first_arg_type, args);
2890
2891 va_end (args);
2892
2893 return ret;
2894 }
2895
2896 /**
2897 * dbus_g_proxy_call_no_reply:
2898 * @proxy: a proxy for a remote interface
2899 * @method: the name of the method to invoke
2900 * @first_arg_type: type of the first argument, or %G_TYPE_INVALID to call
2901 * the method without arguments
2902 * @...: the first argument and any remaining type/argument pairs, followed by
2903 * %G_TYPE_INVALID to terminate the list
2904 *
2905 * Sends a method call message as with dbus_g_proxy_begin_call(), but
2906 * does not ask for a reply or allow you to receive one.
2907 *
2908 * It is an error to call this method on a proxy that has emitted
2909 * the #DBusGProxy::destroy signal.
2910 *
2911 * TODO: this particular function shouldn't die on out of memory,
2912 * since you should be able to do a call with large arguments.
2913 *
2914 * Deprecated: New code should use GDBus instead. The closest equivalent
2915 * is g_dbus_proxy_call() with @callback = %NULL.
2916 */
2917 void
dbus_g_proxy_call_no_reply(DBusGProxy * proxy,const char * method,GType first_arg_type,...)2918 dbus_g_proxy_call_no_reply (DBusGProxy *proxy,
2919 const char *method,
2920 GType first_arg_type,
2921 ...)
2922 {
2923 DBusMessage *message = NULL;
2924 va_list args;
2925 GValueArray *in_args;
2926 DBusGProxyPrivate *priv;
2927
2928 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2929 g_return_if_fail (g_dbus_is_member_name (method));
2930 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2931
2932 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2933
2934 va_start (args, first_arg_type);
2935 DBUS_G_VALUE_ARRAY_COLLECT_ALL (in_args, first_arg_type, args);
2936
2937 if (in_args != NULL)
2938 {
2939 message = dbus_g_proxy_marshal_args_to_message (proxy, method, in_args);
2940
2941 g_value_array_free (in_args);
2942 }
2943
2944 va_end (args);
2945
2946 /* can only happen on a programming error or OOM; we already critical'd */
2947 if (!message)
2948 return;
2949
2950 dbus_message_set_no_reply (message, TRUE);
2951
2952 if (!dbus_connection_send (priv->manager->connection,
2953 message,
2954 NULL))
2955 oom ();
2956
2957 dbus_message_unref (message);
2958 }
2959
2960 /**
2961 * dbus_g_proxy_cancel_call
2962 * @proxy: a proxy for a remote interface
2963 * @call: the pending call ID from dbus_g_proxy_begin_call()
2964 *
2965 * Cancels a pending method call. The method call was normally
2966 * initiated with dbus_g_proxy_begin_call(). This function
2967 * may not be used on pending calls that have already been
2968 * ended with dbus_g_proxy_end_call.
2969 *
2970 * It is an error to call this method on a proxy that has emitted
2971 * the #DBusGProxy::destroy signal.
2972 *
2973 * Deprecated: New code should use GDBus instead. The closest equivalent
2974 * is g_cancellable_cancel().
2975 */
2976 void
dbus_g_proxy_cancel_call(DBusGProxy * proxy,DBusGProxyCall * call)2977 dbus_g_proxy_cancel_call (DBusGProxy *proxy,
2978 DBusGProxyCall *call)
2979 {
2980 guint call_id;
2981 DBusPendingCall *pending;
2982 DBusGProxyPrivate *priv;
2983
2984 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
2985 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
2986
2987 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
2988
2989 call_id = DBUS_G_PROXY_CALL_TO_ID (call);
2990
2991 if (call_id == 0)
2992 {
2993 /* nothing to cancel */
2994 return;
2995 }
2996
2997 pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
2998 g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
2999 g_return_if_fail (pending != NULL);
3000
3001 dbus_pending_call_cancel (pending);
3002 }
3003
3004 /**
3005 * dbus_g_proxy_send:
3006 * @proxy: a proxy for a remote interface
3007 * @message: the message to address and send
3008 * @client_serial: return location for message's serial, or %NULL
3009 *
3010 * Sends a message to the interface we're proxying for. Does not
3011 * block or wait for a reply. The message is only actually written out
3012 * when you return to the main loop or block in
3013 * dbus_g_connection_flush().
3014 *
3015 * The message is modified to be addressed to the target interface.
3016 * That is, a destination name field or whatever is needed will be
3017 * added to the message. The basic point of this function is to add
3018 * the necessary header fields, otherwise it's equivalent to
3019 * dbus_connection_send().
3020 *
3021 * This function adds a reference to the message, so the caller
3022 * still owns its original reference.
3023 *
3024 * It is an error to call this method on a proxy that has emitted
3025 * the #DBusGProxy::destroy signal.
3026 *
3027 * Deprecated: New code should use GDBus instead. The closest equivalent
3028 * is g_dbus_connection_send_message().
3029 */
3030 void
dbus_g_proxy_send(DBusGProxy * proxy,DBusMessage * message,dbus_uint32_t * client_serial)3031 dbus_g_proxy_send (DBusGProxy *proxy,
3032 DBusMessage *message,
3033 dbus_uint32_t *client_serial)
3034 {
3035 DBusGProxyPrivate *priv;
3036
3037 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3038 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3039
3040 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3041
3042 if (priv->name)
3043 {
3044 if (!dbus_message_set_destination (message, priv->name))
3045 g_error ("Out of memory");
3046 }
3047 if (priv->path)
3048 {
3049 if (!dbus_message_set_path (message, priv->path))
3050 g_error ("Out of memory");
3051 }
3052 if (priv->interface)
3053 {
3054 if (!dbus_message_set_interface (message, priv->interface))
3055 g_error ("Out of memory");
3056 }
3057
3058 if (!dbus_connection_send (priv->manager->connection, message, client_serial))
3059 g_error ("Out of memory\n");
3060 }
3061
3062 static void
array_free_all(gpointer array)3063 array_free_all (gpointer array)
3064 {
3065 g_array_free (array, TRUE);
3066 }
3067
3068 /**
3069 * dbus_g_proxy_add_signal:
3070 * @proxy: the proxy for a remote interface
3071 * @signal_name: the name of the signal
3072 * @first_type: the first argument type, or %G_TYPE_INVALID if none
3073 * @...: any subsequent argument types, followed by %G_TYPE_INVALID
3074 *
3075 * Specifies the argument signature of a D-Bus signal. When the signal is
3076 * emitted by the remote object, if the GTypes corresponding to its arguments'
3077 * types do not match the types given here, the signal will be ignored.
3078 *
3079 * It is an error to add the same @signal_name to the same @proxy more than
3080 * once, even if the argument types given are the same.
3081 *
3082 * It is also an error to call this method on a proxy that has emitted
3083 * the #DBusGProxy::destroy signal.
3084 *
3085 * Deprecated: New code should use GDBus instead.
3086 */
3087 void
dbus_g_proxy_add_signal(DBusGProxy * proxy,const char * signal_name,GType first_type,...)3088 dbus_g_proxy_add_signal (DBusGProxy *proxy,
3089 const char *signal_name,
3090 GType first_type,
3091 ...)
3092 {
3093 GQuark q;
3094 char *name;
3095 GArray *gtypesig;
3096 GType gtype;
3097 va_list args;
3098 DBusGProxyPrivate *priv;
3099
3100 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3101 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3102 g_return_if_fail (g_dbus_is_member_name (signal_name));
3103
3104 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3105
3106 name = create_signal_name (priv->interface, signal_name);
3107
3108 q = g_quark_from_string (name);
3109
3110 g_return_if_fail (g_datalist_id_get_data (&priv->signal_signatures, q) == NULL);
3111
3112 gtypesig = g_array_new (FALSE, TRUE, sizeof (GType));
3113
3114 va_start (args, first_type);
3115 gtype = first_type;
3116 while (gtype != G_TYPE_INVALID)
3117 {
3118 g_array_append_val (gtypesig, gtype);
3119 gtype = va_arg (args, GType);
3120 }
3121 va_end (args);
3122
3123 g_datalist_id_set_data_full (&priv->signal_signatures,
3124 q, gtypesig,
3125 array_free_all);
3126
3127 g_free (name);
3128 }
3129
3130 /**
3131 * dbus_g_proxy_connect_signal:
3132 * @proxy: a proxy for a remote interface
3133 * @signal_name: the DBus signal name to listen for
3134 * @handler: the handler to connect
3135 * @data: data to pass to handler
3136 * @free_data_func: callback function to destroy data
3137 *
3138 * Connect a signal handler to a proxy for a remote interface. When
3139 * the remote interface emits the specified signal, the proxy will
3140 * emit a corresponding GLib signal.
3141 *
3142 * It is an error to call this method on a proxy that has emitted
3143 * the #DBusGProxy::destroy signal.
3144 *
3145 * Deprecated: New code should use GDBus instead. The closest equivalent
3146 * is g_dbus_connection_signal_subscribe().
3147 */
3148 void
dbus_g_proxy_connect_signal(DBusGProxy * proxy,const char * signal_name,GCallback handler,void * data,GClosureNotify free_data_func)3149 dbus_g_proxy_connect_signal (DBusGProxy *proxy,
3150 const char *signal_name,
3151 GCallback handler,
3152 void *data,
3153 GClosureNotify free_data_func)
3154 {
3155 char *name;
3156 GClosure *closure;
3157 GQuark q;
3158 DBusGProxyPrivate *priv;
3159
3160 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3161 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3162 g_return_if_fail (g_dbus_is_member_name (signal_name));
3163 g_return_if_fail (handler != NULL);
3164
3165 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3166 name = create_signal_name (priv->interface, signal_name);
3167
3168 q = g_quark_try_string (name);
3169
3170 #ifndef G_DISABLE_CHECKS
3171 if (q == 0 || g_datalist_id_get_data (&priv->signal_signatures, q) == NULL)
3172 {
3173 g_warning ("Must add the signal '%s' with dbus_g_proxy_add_signal() prior to connecting to it\n", name);
3174 g_free (name);
3175 return;
3176 }
3177 #endif
3178
3179 closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
3180
3181 g_signal_connect_closure_by_id (G_OBJECT (proxy),
3182 signals[RECEIVED],
3183 q,
3184 closure, FALSE);
3185
3186 g_free (name);
3187 }
3188
3189 /**
3190 * dbus_g_proxy_disconnect_signal:
3191 * @proxy: a proxy for a remote interface
3192 * @signal_name: the DBus signal name to disconnect
3193 * @handler: the handler to disconnect
3194 * @data: the data that was registered with handler
3195 *
3196 * Disconnect all signal handlers from a proxy that match the given
3197 * criteria.
3198 *
3199 * It is an error to call this method on a proxy that has emitted
3200 * the #DBusGProxy::destroy signal.
3201 *
3202 * Deprecated: New code should use GDBus instead. The closest equivalent
3203 * is g_dbus_connection_signal_unsubscribe().
3204 */
3205 void
dbus_g_proxy_disconnect_signal(DBusGProxy * proxy,const char * signal_name,GCallback handler,void * data)3206 dbus_g_proxy_disconnect_signal (DBusGProxy *proxy,
3207 const char *signal_name,
3208 GCallback handler,
3209 void *data)
3210 {
3211 char *name;
3212 GQuark q;
3213 DBusGProxyPrivate *priv;
3214
3215 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3216 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3217 g_return_if_fail (g_dbus_is_member_name (signal_name));
3218 g_return_if_fail (handler != NULL);
3219
3220 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3221 name = create_signal_name (priv->interface, signal_name);
3222
3223 q = g_quark_try_string (name);
3224
3225 if (q != 0)
3226 {
3227 g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
3228 G_SIGNAL_MATCH_DETAIL |
3229 G_SIGNAL_MATCH_FUNC |
3230 G_SIGNAL_MATCH_DATA,
3231 signals[RECEIVED],
3232 q,
3233 NULL,
3234 G_CALLBACK (handler), data);
3235 }
3236 else
3237 {
3238 g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
3239 name);
3240 }
3241
3242 g_free (name);
3243 }
3244
3245 /**
3246 * dbus_g_proxy_set_default_timeout:
3247 * @proxy: a proxy for a remote interface
3248 * @timeout: the timeout in milliseconds, or -1 to reset to the libdbus default
3249 *
3250 * Sets the default timeout to use for a proxy. This timeout will be
3251 * used in calls where the timeout is not specified, or is specified to be -1.
3252 * If this timeout is also set to -1, libdbus will use a reasonable default
3253 * value.
3254 *
3255 * This is useful for long-running operations that takes longer than
3256 * the default timeout (which is a on the order of magnitude of tens
3257 * of seconds). For some applications, consider using a pattern where
3258 * the method returns once the operation is underway
3259 * (e.g. immediately) and emits a signal when the operation terminates
3260 * (though beware of leaking information with/in the signal return value).
3261 *
3262 * It is an error to call this method on a proxy that has emitted
3263 * the #DBusGProxy::destroy signal.
3264 *
3265 * Since: 0.75
3266 *
3267 * Deprecated: New code should use GDBus instead.
3268 */
3269 void
dbus_g_proxy_set_default_timeout(DBusGProxy * proxy,int timeout)3270 dbus_g_proxy_set_default_timeout (DBusGProxy *proxy,
3271 int timeout)
3272 {
3273 DBusGProxyPrivate *priv;
3274
3275 g_return_if_fail (DBUS_IS_G_PROXY (proxy));
3276 g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy));
3277 g_return_if_fail (timeout >= 0 || timeout == -1);
3278
3279 priv = DBUS_G_PROXY_GET_PRIVATE(proxy);
3280 priv->default_timeout = timeout;
3281 }
3282