2003-10-20 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / glib / dbus-gproxy.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gcall.c convenience routines for calling methods, etc.
3  *
4  * Copyright (C) 2003  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23 #include "dbus-glib.h"
24 #include <string.h>
25
26 /**
27  * @addtogroup DBusGLibInternals
28  *
29  * @{
30  */
31
32 typedef struct DBusGProxyManager DBusGProxyManager;
33
34 /**
35  * Internals of DBusGProxy
36  */
37 struct DBusGProxy
38 {
39   GObject parent;             /**< Parent instance */
40   
41   DBusGProxyManager *manager; /**< Proxy manager */
42   char *service;              /**< Service messages go to or NULL */
43   char *path;                 /**< Path messages go to or NULL */
44   char *interface;            /**< Interface messages go to or NULL */
45 };
46
47 /**
48  * Class struct for DBusGProxy
49  */
50 struct DBusGProxyClass
51 {
52   GObjectClass parent_class;  
53 };
54
55 static void dbus_gproxy_init          (DBusGProxy      *proxy);
56 static void dbus_gproxy_class_init    (DBusGProxyClass *klass);
57 static void dbus_gproxy_finalize      (GObject         *object);
58 static void dbus_gproxy_dispose       (GObject         *object);
59 static void dbus_gproxy_destroy       (DBusGProxy      *proxy);
60 static void dbus_gproxy_emit_received (DBusGProxy      *proxy,
61                                        DBusMessage     *message);
62
63
64 /**
65  * A list of proxies with a given service+path+interface, used to route incoming
66  * signals.
67  */
68 typedef struct
69 {
70   GSList *proxies;
71
72   char name[4]; /**< service (empty string for none), nul byte,
73                  *   path, nul byte,
74                  *   interface, nul byte
75                  */
76   
77 } DBusGProxyList;
78
79 /**
80  * DBusGProxyManager's primary task is to route signals to the proxies
81  * those signals are emitted on. In order to do this it also has to
82  * track the owners of the services proxies are bound to.
83  */
84 struct DBusGProxyManager
85 {
86   GStaticMutex lock; /**< Thread lock */
87   int refcount;      /**< Reference count */
88   DBusConnection *connection; /**< Connection we're associated with. */
89
90   GHashTable *proxy_lists; /**< Hash used to route incoming signals
91                             *   and iterate over proxies
92                             */
93
94 };
95
96 static void              dbus_gproxy_manager_ref    (DBusGProxyManager *manager);
97 static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection    *connection,
98                                                      DBusMessage       *message,
99                                                      void              *user_data);
100
101 /** Lock the DBusGProxyManager */
102 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
103 /** Unlock the DBusGProxyManager */
104 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
105
106 static int gproxy_manager_slot = -1;
107
108 /* Lock controlling get/set manager as data on each connection */
109 static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
110
111 static DBusGProxyManager*
112 dbus_gproxy_manager_get (DBusConnection *connection)
113 {
114   DBusGProxyManager *manager;
115
116   dbus_connection_allocate_data_slot (&gproxy_manager_slot);
117   if (gproxy_manager_slot < 0)
118     g_error ("out of memory");
119   
120   g_static_mutex_lock (&connection_gproxy_lock);
121   
122   manager = dbus_connection_get_data (connection, gproxy_manager_slot);
123   if (manager != NULL)
124     {
125       dbus_connection_free_data_slot (&gproxy_manager_slot);
126       dbus_gproxy_manager_ref (manager);
127       g_static_mutex_unlock (&connection_gproxy_lock);
128       return manager;
129     }
130   
131   manager = g_new0 (DBusGProxyManager, 1);
132
133   manager->refcount = 1;
134   manager->connection = connection;
135   
136   g_static_mutex_init (&manager->lock);
137
138   /* Proxy managers keep the connection alive, which means that
139    * DBusGProxy indirectly does. To free a connection you have to free
140    * all the proxies referring to it.
141    */
142   dbus_connection_ref (manager->connection);
143
144   dbus_connection_set_data (connection, gproxy_manager_slot,
145                             manager, NULL);
146
147   dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
148                               manager, NULL);
149   
150   g_static_mutex_unlock (&connection_gproxy_lock);
151   
152   return manager;
153 }
154
155 static void
156 dbus_gproxy_manager_ref (DBusGProxyManager *manager)
157 {
158   g_assert (manager != NULL);
159   g_assert (manager->refcount > 0);
160
161   LOCK_MANAGER (manager);
162   
163   manager->refcount += 1;
164
165   UNLOCK_MANAGER (manager);
166 }
167
168 static void
169 dbus_gproxy_manager_unref (DBusGProxyManager *manager)
170 {
171   g_assert (manager != NULL);
172   g_assert (manager->refcount > 0);
173
174   LOCK_MANAGER (manager);
175   manager->refcount -= 1;
176   if (manager->refcount == 0)
177     {
178       UNLOCK_MANAGER (manager);
179
180       if (manager->proxy_lists)
181         {
182           /* can't have any proxies left since they hold
183            * a reference to the proxy manager.
184            */
185           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
186           
187           g_hash_table_destroy (manager->proxy_lists);
188           manager->proxy_lists = NULL;
189         }
190       
191       g_static_mutex_free (&manager->lock);
192
193       g_static_mutex_lock (&connection_gproxy_lock);
194
195       dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
196                                      manager);
197       
198       dbus_connection_set_data (manager->connection,
199                                 gproxy_manager_slot,
200                                 NULL, NULL);
201
202       g_static_mutex_unlock (&connection_gproxy_lock);
203       
204       dbus_connection_unref (manager->connection);
205       g_free (manager);
206
207       dbus_connection_free_data_slot (&gproxy_manager_slot);
208     }
209   else
210     {
211       UNLOCK_MANAGER (manager);
212     }
213 }
214
215 static guint
216 tristring_hash (gconstpointer key)
217 {
218   const char *p = key;
219   guint h = *p;
220
221   if (h)
222     {
223       for (p += 1; *p != '\0'; p++)
224         h = (h << 5) - h + *p;
225     }
226
227   /* skip nul and do the next substring */
228   for (p += 1; *p != '\0'; p++)
229     h = (h << 5) - h + *p;
230
231   /* skip nul again and another substring */
232   for (p += 1; *p != '\0'; p++)
233     h = (h << 5) - h + *p;
234   
235   return h;
236 }
237
238 static gboolean
239 strequal_len (const char *a,
240               const char *b,
241               size_t     *lenp)
242 {
243   size_t a_len;
244   size_t b_len;
245
246   a_len = strlen (a);
247   b_len = strlen (b);
248
249   if (a_len != b_len)
250     return FALSE;
251
252   if (memcmp (a, b, a_len) != 0)
253     return FALSE;
254   
255   *lenp = a_len;
256
257   return TRUE;
258 }
259
260 static gboolean
261 tristring_equal (gconstpointer  a,
262                  gconstpointer  b)
263 {
264   const char *ap = a;
265   const char *bp = b;
266   size_t len;
267
268   if (!strequal_len (ap, bp, &len))
269     return FALSE;
270
271   ap += len + 1;
272   bp += len + 1;
273
274   if (!strequal_len (ap, bp, &len))
275     return FALSE;
276
277   ap += len + 1;
278   bp += len + 1;
279
280   if (strcmp (ap, bp) != 0)
281     return FALSE;
282   
283   return TRUE;
284 }
285
286 static char*
287 tristring_alloc_from_strings (size_t      padding_before,
288                               const char *service,
289                               const char *path,
290                               const char *interface)
291 {
292   size_t service_len, iface_len, path_len, len;
293   char *tri;
294   
295   if (service)
296     service_len = strlen (service);
297   else
298     service_len = 0;
299
300   path_len = strlen (path);
301   
302   iface_len = strlen (interface);
303
304   tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
305
306   len = padding_before;
307   
308   if (service)
309     memcpy (&tri[len], service, service_len);
310
311   len += service_len;
312   tri[len] = '\0';
313   len += 1;
314
315   g_assert (len == (padding_before + service_len + 1));
316   
317   memcpy (&tri[len], path, path_len);
318   len += path_len;
319   tri[len] = '\0';
320   len += 1;
321
322   g_assert (len == (padding_before + service_len + path_len + 2));
323   
324   memcpy (&tri[len], interface, iface_len);
325   len += iface_len;
326   tri[len] = '\0';
327   len += 1;
328
329   g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
330
331   return tri;
332 }
333
334 static char*
335 tristring_from_proxy (DBusGProxy *proxy)
336 {
337   return tristring_alloc_from_strings (0,
338                                        proxy->service,
339                                        proxy->path,
340                                        proxy->interface);
341 }
342
343 static char*
344 tristring_from_message (DBusMessage *message)
345 {
346   return tristring_alloc_from_strings (0,
347                                        dbus_message_get_sender (message),
348                                        dbus_message_get_path (message),
349                                        dbus_message_get_interface (message));
350 }
351
352 static DBusGProxyList*
353 gproxy_list_new (DBusGProxy *first_proxy)
354 {
355   DBusGProxyList *list;
356   
357   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
358                                                first_proxy->service,
359                                                first_proxy->path,
360                                                first_proxy->interface);
361   list->proxies = NULL;
362
363   return list;
364 }
365
366 static void
367 gproxy_list_free (DBusGProxyList *list)
368 {
369   /* we don't hold a reference to the proxies in the list,
370    * as they ref the GProxyManager
371    */
372   g_slist_free (list->proxies);  
373
374   g_free (list);
375 }
376
377 static char*
378 gproxy_get_match_rule (DBusGProxy *proxy)
379 {
380   /* FIXME Escaping is required here */
381   
382   if (proxy->service)
383     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
384                             proxy->service, proxy->path, proxy->interface);
385   else
386     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
387                             proxy->path, proxy->interface);
388 }
389
390 static void
391 dbus_gproxy_manager_register (DBusGProxyManager *manager,
392                               DBusGProxy        *proxy)
393 {
394   DBusGProxyList *list;
395
396   LOCK_MANAGER (manager);
397
398   if (manager->proxy_lists == NULL)
399     {
400       list = NULL;
401       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
402                                                     tristring_equal,
403                                                     NULL,
404                                                     (GFreeFunc) gproxy_list_free);
405     }
406   else
407     {
408       char *tri;
409
410       tri = tristring_from_proxy (proxy);
411       
412       list = g_hash_table_lookup (manager->proxy_lists, tri);
413
414       g_free (tri);
415     }
416       
417   if (list == NULL)
418     {
419       list = gproxy_list_new (proxy);
420       
421       g_hash_table_replace (manager->proxy_lists,
422                             list->name, list);
423     }
424
425   if (list->proxies == NULL)
426     {
427       /* We have to add the match rule to the server,
428        * but FIXME only if the server is a message bus,
429        * not if it's a peer.
430        */
431       char *rule;
432
433       rule = gproxy_get_match_rule (proxy);
434       
435       /* We don't check for errors; it's not like anyone would handle them,
436        * and we don't want a round trip here.
437        */
438       dbus_bus_add_match (manager->connection,
439                           rule, NULL);
440
441       g_free (rule);
442     }
443
444   g_assert (g_slist_find (list->proxies, proxy) == NULL);
445   
446   list->proxies = g_slist_prepend (list->proxies, proxy);
447   
448   UNLOCK_MANAGER (manager);
449 }
450
451 static void
452 dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
453                                 DBusGProxy        *proxy)
454 {
455   DBusGProxyList *list;
456   char *tri;
457   
458   LOCK_MANAGER (manager);
459
460 #ifndef G_DISABLE_CHECKS
461   if (manager->proxy_lists == NULL)
462     {
463       g_warning ("Trying to unregister a proxy but there aren't any registered");
464       return;
465     }
466 #endif
467
468   tri = tristring_from_proxy (proxy);
469   
470   list = g_hash_table_lookup (manager->proxy_lists, tri);
471
472 #ifndef G_DISABLE_CHECKS
473   if (list == NULL)
474     {
475       g_warning ("Trying to unregister a proxy but it isn't registered");
476       return;
477     }
478 #endif
479
480   g_assert (g_slist_find (list->proxies, proxy) != NULL);
481   
482   list->proxies = g_slist_remove (list->proxies, proxy);
483
484   g_assert (g_slist_find (list->proxies, proxy) == NULL);
485
486   if (list->proxies == NULL)
487     {
488       g_hash_table_remove (manager->proxy_lists,
489                            tri);
490       list = NULL;
491     }
492   
493   if (g_hash_table_size (manager->proxy_lists) == 0)
494     {
495       g_hash_table_destroy (manager->proxy_lists);
496       manager->proxy_lists = NULL;
497     }
498
499   g_free (tri);
500       
501   UNLOCK_MANAGER (manager);
502 }
503
504 static void
505 list_proxies_foreach (gpointer key,
506                       gpointer value,
507                       gpointer user_data)
508 {
509   DBusGProxyList *list;
510   GSList **ret;
511   GSList *tmp;
512   
513   list = value;
514   ret = user_data;
515
516   tmp = list->proxies;
517   while (tmp != NULL)
518     {
519       DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
520
521       g_object_ref (proxy);
522       *ret = g_slist_prepend (*ret, proxy);
523       
524       tmp = tmp->next;
525     }
526 }
527
528 static GSList*
529 dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
530 {
531   GSList *ret;
532
533   ret = NULL;
534
535   if (manager->proxy_lists)
536     {
537       g_hash_table_foreach (manager->proxy_lists,
538                             list_proxies_foreach,
539                             &ret);
540     }
541
542   return ret;
543 }
544
545 static DBusHandlerResult
546 dbus_gproxy_manager_filter (DBusConnection    *connection,
547                             DBusMessage       *message,
548                             void              *user_data)
549 {
550   DBusGProxyManager *manager;
551   
552   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
553     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
554
555   manager = user_data;
556
557   dbus_gproxy_manager_ref (manager);
558   
559   LOCK_MANAGER (manager);
560   
561   if (dbus_message_is_signal (message,
562                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
563                               "Disconnected"))
564     {
565       /* Destroy all the proxies, quite possibly resulting in unreferencing
566        * the proxy manager and the connection as well.
567        */
568       GSList *all;
569       GSList *tmp;
570
571       all = dbus_gproxy_manager_list_all (manager);
572
573       tmp = all;
574       while (tmp != NULL)
575         {
576           DBusGProxy *proxy;
577
578           proxy = DBUS_GPROXY (tmp->data);
579
580           UNLOCK_MANAGER (manager);
581           dbus_gproxy_destroy (proxy);
582           g_object_unref (G_OBJECT (proxy));
583           LOCK_MANAGER (manager);
584           
585           tmp = tmp->next;
586         }
587
588       g_slist_free (all);
589
590 #ifndef G_DISABLE_CHECKS
591       if (manager->proxy_lists != NULL)
592         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.");
593 #endif
594     }
595   else
596     {
597       char *tri;
598       DBusGProxyList *list;
599       
600       tri = tristring_from_message (message);
601
602       if (manager->proxy_lists)
603         list = g_hash_table_lookup (manager->proxy_lists, tri);
604       else
605         list = NULL;
606
607 #if 0
608       g_print ("proxy got %s,%s,%s = list %p\n",
609                tri,
610                tri + strlen (tri) + 1,
611                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
612                list);
613 #endif
614       
615       g_free (tri);
616
617       /* Emit the signal */
618       
619       if (list != NULL)
620         {
621           GSList *tmp;
622           GSList *copy;
623
624           copy = g_slist_copy (list->proxies);
625           g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
626           
627           tmp = copy;
628           while (tmp != NULL)
629             {
630               DBusGProxy *proxy;
631
632               proxy = DBUS_GPROXY (tmp->data);
633
634               UNLOCK_MANAGER (manager);
635               dbus_gproxy_emit_received (proxy, message);
636               g_object_unref (G_OBJECT (proxy));
637               LOCK_MANAGER (manager);
638               
639               tmp = tmp->next;
640             }
641
642           g_slist_free (copy);
643         }
644     }
645
646   UNLOCK_MANAGER (manager);
647   dbus_gproxy_manager_unref (manager);
648   
649   /* "Handling" signals doesn't make sense, they are for everyone
650    * who cares
651    */
652   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
653 }
654
655
656
657 /*      ---------- DBusGProxy --------------   */
658
659
660
661 enum
662 {
663   DESTROY,
664   RECEIVED,
665   LAST_SIGNAL
666 };
667
668 static void *parent_class;
669 static guint signals[LAST_SIGNAL] = { 0 };
670
671 static void
672 dbus_gproxy_init (DBusGProxy *proxy)
673 {
674   /* Nothing */
675 }
676
677 static void
678 dbus_gproxy_class_init (DBusGProxyClass *klass)
679 {
680   GObjectClass *object_class = G_OBJECT_CLASS (klass);
681   
682   parent_class = g_type_class_peek_parent (klass);
683   
684   object_class->finalize = dbus_gproxy_finalize;
685   object_class->dispose = dbus_gproxy_dispose;
686   
687   signals[DESTROY] =
688     g_signal_new ("destroy",
689                   G_OBJECT_CLASS_TYPE (object_class),
690                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
691                   0,
692                   NULL, NULL,
693                   g_cclosure_marshal_VOID__VOID,
694                   G_TYPE_NONE, 0);
695   
696   signals[RECEIVED] =
697     g_signal_new ("received",
698                   G_OBJECT_CLASS_TYPE (object_class),
699                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
700                   0,
701                   NULL, NULL,
702                   g_cclosure_marshal_VOID__BOXED,
703                   G_TYPE_NONE, 1,
704                   DBUS_TYPE_MESSAGE);
705 }
706
707
708 static void
709 dbus_gproxy_dispose (GObject *object)
710 {
711   DBusGProxy *proxy;
712
713   proxy = DBUS_GPROXY (object);
714
715   g_signal_emit (object, signals[DESTROY], 0);
716   
717   G_OBJECT_CLASS (parent_class)->dispose (object);
718 }
719
720 static void
721 dbus_gproxy_finalize (GObject *object)
722 {
723   DBusGProxy *proxy;
724
725   proxy = DBUS_GPROXY (object);
726
727   if (proxy->manager)
728     {
729       dbus_gproxy_manager_unregister (proxy->manager, proxy);
730       dbus_gproxy_manager_unref (proxy->manager);
731     }
732   
733   g_free (proxy->service);
734   g_free (proxy->path);
735   g_free (proxy->interface);
736   
737   G_OBJECT_CLASS (parent_class)->finalize (object);
738 }
739
740 static void
741 dbus_gproxy_destroy (DBusGProxy *proxy)
742 {
743   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
744    * from GtkObject?
745    */
746   g_object_run_dispose (G_OBJECT (proxy));
747 }
748
749 static char*
750 create_signal_detail (const char *interface,
751                       const char *signal)
752 {
753   GString *str;
754
755   str = g_string_new (interface);
756
757   g_string_append (str, ".");
758
759   g_string_append (str, signal);
760
761   return g_string_free (str, FALSE);
762 }
763
764 static void
765 dbus_gproxy_emit_received (DBusGProxy  *proxy,
766                            DBusMessage *message)
767 {
768   const char *interface;
769   const char *signal;
770   char *detail;
771   GQuark q;
772   
773   interface = dbus_message_get_interface (message);
774   signal = dbus_message_get_member (message);
775
776   g_assert (interface != NULL);
777   g_assert (signal != NULL);
778
779   detail = create_signal_detail (interface, signal);
780
781   /* If the quark isn't preexisting, there's no way there
782    * are any handlers connected. We don't want to create
783    * extra quarks for every possible signal.
784    */
785   q = g_quark_try_string (detail);
786
787   if (q != 0)
788     g_signal_emit (G_OBJECT (proxy),
789                    signals[RECEIVED],
790                    q,
791                    message);
792
793   g_free (detail);
794 }
795
796 /** @} End of DBusGLibInternals */
797
798 /** @addtogroup DBusGLib
799  * @{
800  */
801
802 /**
803  * Standard GObject get_type() function for DBusGProxy.
804  *
805  * @returns type ID for DBusGProxy class
806  */
807 GType
808 dbus_gproxy_get_type (void)
809 {
810   static GType object_type = 0;
811
812   if (!object_type)
813     {
814       static const GTypeInfo object_info =
815         {
816           sizeof (DBusGProxyClass),
817           (GBaseInitFunc) NULL,
818           (GBaseFinalizeFunc) NULL,
819           (GClassInitFunc) dbus_gproxy_class_init,
820           NULL,           /* class_finalize */
821           NULL,           /* class_data */
822           sizeof (DBusGProxy),
823           0,              /* n_preallocs */
824           (GInstanceInitFunc) dbus_gproxy_init,
825         };
826       
827       object_type = g_type_register_static (G_TYPE_OBJECT,
828                                             "DBusGProxy",
829                                             &object_info, 0);
830     }
831   
832   return object_type;
833 }
834
835 static DBusGProxy*
836 dbus_gproxy_new (DBusConnection *connection,
837                  const char     *service_name,
838                  const char     *path_name,
839                  const char     *interface_name)
840 {
841   DBusGProxy *proxy;
842
843   g_assert (connection != NULL);
844   
845   proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
846
847   /* These should all be construct-only mandatory properties,
848    * for now we just don't let people use g_object_new().
849    */
850   
851   proxy->manager = dbus_gproxy_manager_get (connection);
852   
853   proxy->service = g_strdup (service_name);
854   proxy->path = g_strdup (path_name);
855   proxy->interface = g_strdup (interface_name);
856
857   dbus_gproxy_manager_register (proxy->manager, proxy);
858   
859   return proxy;
860 }
861
862 /**
863  * Creates a new proxy for a remote interface exported by a service on
864  * a message bus. Method calls and signal connections over this proxy
865  * will go to the service owner; the service owner is expected to
866  * support the given interface name. THE SERVICE OWNER MAY CHANGE OVER
867  * TIME, for example between two different method calls. If you need a
868  * fixed owner, you need to request the current owner and bind a proxy
869  * to that rather than to the generic service name; see
870  * dbus_gproxy_new_for_service_owner().
871  *
872  * A service-associated proxy only makes sense with a message bus,
873  * not for app-to-app direct dbus connections.
874  *
875  * This proxy will only emit the "destroy" signal if the #DBusConnection
876  * is disconnected or the proxy is has no remaining references.
877  *
878  * @param connection the connection to the remote bus
879  * @param service_name name of the service on the message bus
880  * @param path_name name of the object inside the service to call methods on
881  * @param interface_name name of the interface to call methods on
882  * @returns new proxy object
883  */
884 DBusGProxy*
885 dbus_gproxy_new_for_service (DBusConnection *connection,
886                              const char     *service_name,
887                              const char     *path_name,
888                              const char     *interface_name)
889 {
890   DBusGProxy *proxy;
891
892   g_return_val_if_fail (connection != NULL, NULL);
893   g_return_val_if_fail (service_name != NULL, NULL);
894   g_return_val_if_fail (path_name != NULL, NULL);
895   g_return_val_if_fail (interface_name != NULL, NULL);
896   
897   proxy = dbus_gproxy_new (connection, service_name,
898                            path_name, interface_name);
899
900   return proxy;
901 }
902
903 /**
904  * Similar to dbus_gproxy_new_for_service(), but makes a round-trip
905  * request to the message bus to get the current service owner, then
906  * binds the proxy specifically to the current owner. As a result, the
907  * service owner will not change over time, and the proxy will emit
908  * the "destroy" signal when the owner disappears from the message
909  * bus.
910  *
911  * An example of the difference between dbus_gproxy_new_for_service()
912  * and dbus_gproxy_new_for_service_owner(): if you pass the service name
913  * "org.freedesktop.Database" dbus_gproxy_new_for_service() remains bound
914  * to that name as it changes owner. dbus_gproxy_new_for_service_owner()
915  * will fail if the service has no owner. If the service has an owner,
916  * dbus_gproxy_new_for_service_owner() will bind to the unique name
917  * of that owner rather than the generic service name.
918  * 
919  * @param connection the connection to the remote bus
920  * @param service_name name of the service on the message bus
921  * @param path_name name of the object inside the service to call methods on
922  * @param interface_name name of the interface to call methods on
923  * @param error return location for an error
924  * @returns new proxy object, or #NULL on error
925  */
926 DBusGProxy*
927 dbus_gproxy_new_for_service_owner (DBusConnection           *connection,
928                                    const char               *service_name,
929                                    const char               *path_name,
930                                    const char               *interface_name,
931                                    GError                  **error)
932 {
933   g_return_val_if_fail (connection != NULL, NULL);
934   g_return_val_if_fail (service_name != NULL, NULL);
935   g_return_val_if_fail (path_name != NULL, NULL);
936   g_return_val_if_fail (interface_name != NULL, NULL);
937
938
939 }
940
941 /**
942  * Creates a proxy for an object in peer application (one
943  * we're directly connected to). That is, this function is
944  * intended for use when there's no message bus involved,
945  * we're doing a simple 1-to-1 communication between two
946  * applications.
947  *
948  *
949  * @param connection the connection to the peer
950  * @param path_name name of the object inside the peer to call methods on
951  * @param interface_name name of the interface to call methods on
952  * @returns new proxy object
953  * 
954  */
955 DBusGProxy*
956 dbus_gproxy_new_for_peer (DBusConnection           *connection,
957                           const char               *path_name,
958                           const char               *interface_name)
959 {
960   DBusGProxy *proxy;
961   
962   g_return_val_if_fail (connection != NULL, NULL);
963   g_return_val_if_fail (path_name != NULL, NULL);
964   g_return_val_if_fail (interface_name != NULL, NULL);
965
966   proxy = dbus_gproxy_new (connection, NULL,
967                            path_name, interface_name);
968
969   return proxy;
970 }
971
972 /**
973  * Invokes a method on a remote interface. This function does not
974  * block; instead it returns an opaque #DBusPendingCall object that
975  * tracks the pending call.  The method call will not be sent over the
976  * wire until the application returns to the main loop, or blocks in
977  * dbus_connection_flush() to write out pending data.  The call will
978  * be completed after a timeout, or when a reply is received.
979  * To collect the results of the call (which may be an error,
980  * or a reply), use dbus_gproxy_end_call().
981  *
982  * @todo this particular function shouldn't die on out of memory,
983  * since you should be able to do a call with large arguments.
984  * 
985  * @param proxy a proxy for a remote interface
986  * @param method the name of the method to invoke
987  * @param first_arg_type type of the first argument
988  *
989  * @returns opaque pending call object
990  *  */
991 DBusPendingCall*
992 dbus_gproxy_begin_call (DBusGProxy *proxy,
993                         const char *method,
994                         int         first_arg_type,
995                         ...)
996 {
997   DBusPendingCall *pending;
998   DBusMessage *message;
999   va_list args;
1000   
1001   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
1002
1003   message = dbus_message_new_method_call (proxy->service,
1004                                           proxy->path,
1005                                           proxy->interface,
1006                                           method);
1007   if (message == NULL)
1008     goto oom;
1009
1010   va_start (args, first_arg_type);
1011   if (!dbus_message_append_args_valist (message, first_arg_type,
1012                                         args))
1013     goto oom;
1014   va_end (args);
1015
1016   if (!dbus_connection_send_with_reply (proxy->manager->connection,
1017                                         message,
1018                                         &pending,
1019                                         -1))
1020     goto oom;
1021
1022   return pending;
1023
1024  oom:
1025   /* FIXME we should create a pending call that's
1026    * immediately completed with an error status without
1027    * ever going on the wire.
1028    */
1029   
1030   g_error ("Out of memory");
1031   return NULL;
1032 }
1033
1034 /**
1035  * Collects the results of a method call. The method call was normally
1036  * initiated with dbus_gproxy_end_call(). This function will block if
1037  * the results haven't yet been received; use
1038  * dbus_pending_call_set_notify() to be notified asynchronously that a
1039  * pending call has been completed. Use
1040  * dbus_pending_call_get_completed() to check whether a call has been
1041  * completed. If it's completed, it will not block.
1042  *
1043  * If the call results in an error, the error is set as normal for
1044  * GError and the function returns #FALSE.
1045  *
1046  * Otherwise, the "out" parameters and return value of the
1047  * method are stored in the provided varargs list.
1048  * The list should be terminated with DBUS_TYPE_INVALID.
1049  *
1050  * This function doesn't affect the reference count of the
1051  * #DBusPendingCall, the caller of dbus_gproxy_begin_call() still owns
1052  * a reference.
1053  *
1054  * @param proxy a proxy for a remote interface
1055  * @param pending the pending call from dbus_gproxy_begin_call()
1056  * @param error return location for an error
1057  * @param first_arg_type type of first "out" argument
1058  * @returns #FALSE if an error is set */
1059 gboolean
1060 dbus_gproxy_end_call (DBusGProxy          *proxy,
1061                       DBusPendingCall     *pending,
1062                       GError             **error,
1063                       int                  first_arg_type,
1064                       ...)
1065 {
1066   DBusMessage *message;
1067   va_list args;
1068   DBusError derror;
1069   
1070   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
1071   g_return_val_if_fail (pending != NULL, FALSE);
1072
1073   dbus_pending_call_block (pending);
1074   message = dbus_pending_call_get_reply (pending);
1075
1076   g_assert (message != NULL);
1077
1078   dbus_error_init (&derror);
1079
1080   switch (dbus_message_get_type (message))
1081     {
1082     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
1083       va_start (args, first_arg_type);
1084       if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
1085         {
1086           va_end (args);
1087           goto error;
1088         }
1089       va_end (args);
1090
1091       return TRUE;
1092       
1093     case DBUS_MESSAGE_TYPE_ERROR:
1094       dbus_set_error_from_message (&derror, message);
1095       goto error;
1096
1097     default:
1098       dbus_set_error (&derror, DBUS_ERROR_FAILED,
1099                       "Reply was neither a method return nor an exception");
1100       goto error;
1101     }
1102
1103  error:
1104   dbus_set_g_error (error, &derror);
1105   dbus_error_free (&derror);
1106   return FALSE;
1107 }
1108
1109 /**
1110  * Sends a method call message as with dbus_gproxy_begin_call(), but
1111  * does not ask for a reply or allow you to receive one.
1112  *
1113  * @todo this particular function shouldn't die on out of memory,
1114  * since you should be able to do a call with large arguments.
1115  * 
1116  * @param proxy a proxy for a remote interface
1117  * @param method the name of the method to invoke
1118  * @param first_arg_type type of the first argument
1119  */
1120 void
1121 dbus_gproxy_call_no_reply (DBusGProxy               *proxy,
1122                            const char               *method,
1123                            int                       first_arg_type,
1124                            ...)
1125 {
1126   DBusMessage *message;
1127   va_list args;
1128   
1129   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1130
1131   message = dbus_message_new_method_call (proxy->service,
1132                                           proxy->path,
1133                                           proxy->interface,
1134                                           method);
1135   if (message == NULL)
1136     goto oom;
1137
1138   dbus_message_set_no_reply (message, TRUE);
1139   
1140   va_start (args, first_arg_type);
1141   if (!dbus_message_append_args_valist (message, first_arg_type,
1142                                         args))
1143     goto oom;
1144   va_end (args);
1145
1146   if (!dbus_connection_send (proxy->manager->connection,
1147                              message,
1148                              NULL))
1149     goto oom;
1150
1151   return;
1152   
1153  oom:
1154   g_error ("Out of memory");
1155 }
1156
1157 /**
1158  * Sends a message to the interface we're proxying for.  Does not
1159  * block or wait for a reply. The message is only actually written out
1160  * when you return to the main loop or block in
1161  * dbus_connection_flush().
1162  *
1163  * The message is modified to be addressed to the target interface.
1164  * That is, a destination service field or whatever is needed will be
1165  * added to the message. The basic point of this function is to add
1166  * the necessary header fields, otherwise it's equivalent to
1167  * dbus_connection_send().
1168  *
1169  * This function adds a reference to the message, so the caller
1170  * still owns its original reference.
1171  * 
1172  * @param proxy a proxy for a remote interface
1173  * @param message the message to address and send
1174  * @param client_serial return location for message's serial, or #NULL */
1175 void
1176 dbus_gproxy_send (DBusGProxy          *proxy,
1177                   DBusMessage         *message,
1178                   dbus_uint32_t       *client_serial)
1179 {
1180   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1181   
1182   if (proxy->service)
1183     {
1184       if (!dbus_message_set_destination (message, proxy->service))
1185         g_error ("Out of memory");
1186     }
1187   if (proxy->path)
1188     {
1189       if (!dbus_message_set_path (message, proxy->path))
1190         g_error ("Out of memory");
1191     }
1192   if (proxy->interface)
1193     {
1194       if (!dbus_message_set_interface (message, proxy->interface))
1195         g_error ("Out of memory");
1196     }
1197   
1198   if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
1199     g_error ("Out of memory\n");
1200 }
1201
1202 void
1203 dbus_gproxy_connect_signal (DBusGProxy             *proxy,
1204                             const char             *signal_name,
1205                             DBusGProxySignalHandler handler,
1206                             void                   *data,
1207                             GClosureNotify          free_data_func)
1208 {
1209   GClosure *closure;
1210   char *detail;
1211
1212   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1213   g_return_if_fail (signal_name != NULL);
1214   g_return_if_fail (handler != NULL);
1215   
1216   detail = create_signal_detail (proxy->interface, signal_name);
1217   
1218   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
1219   g_signal_connect_closure_by_id (G_OBJECT (proxy),
1220                                   signals[RECEIVED],
1221                                   g_quark_from_string (detail),
1222                                   closure, FALSE);
1223
1224   g_free (detail);
1225 }
1226
1227 void
1228 dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,
1229                                const char             *signal_name,
1230                                DBusGProxySignalHandler handler,
1231                                void                   *data)
1232 {
1233   char *detail;
1234   GQuark q;
1235   
1236   g_return_if_fail (DBUS_IS_GPROXY (proxy));
1237   g_return_if_fail (signal_name != NULL);
1238   g_return_if_fail (handler != NULL);
1239
1240   detail = create_signal_detail (proxy->interface, signal_name);
1241   q = g_quark_try_string (detail);
1242   g_free (detail);
1243
1244 #ifndef G_DISABLE_CHECKS
1245   if (q == 0)
1246     {
1247       g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
1248                  G_GNUC_FUNCTION, signal_name);
1249       return;
1250     }
1251 #endif
1252
1253   g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
1254                                         G_SIGNAL_MATCH_DETAIL |
1255                                         G_SIGNAL_MATCH_FUNC   |
1256                                         G_SIGNAL_MATCH_DATA,
1257                                         signals[RECEIVED],
1258                                         q,
1259                                         NULL,
1260                                         G_CALLBACK (handler), data);
1261 }
1262
1263 /** @} End of DBusGLib public */
1264
1265 #ifdef DBUS_BUILD_TESTS
1266
1267 /**
1268  * @ingroup DBusGLibInternals
1269  * Unit test for GLib proxy functions
1270  * @returns #TRUE on success.
1271  */
1272 dbus_bool_t
1273 _dbus_gproxy_test (void)
1274 {
1275   
1276   
1277   return TRUE;
1278 }
1279
1280 #endif /* DBUS_BUILD_TESTS */