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