Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-gproxy.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-gcall.c convenience routines for calling methods, etc.
00003  *
00004  * Copyright (C) 2003  Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 1.2
00007  * 
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  * 
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 #include "dbus-glib.h"
00024 #include <string.h>
00025 
00032 typedef struct DBusGProxyManager DBusGProxyManager;
00033 
00037 struct DBusGProxy
00038 {
00039   GObject parent;             
00041   DBusGProxyManager *manager; 
00042   char *service;              
00043   char *path;                 
00044   char *interface;            
00045 };
00046 
00050 struct DBusGProxyClass
00051 {
00052   GObjectClass parent_class;  
00053 };
00054 
00055 static void dbus_gproxy_init          (DBusGProxy      *proxy);
00056 static void dbus_gproxy_class_init    (DBusGProxyClass *klass);
00057 static void dbus_gproxy_finalize      (GObject         *object);
00058 static void dbus_gproxy_dispose       (GObject         *object);
00059 static void dbus_gproxy_destroy       (DBusGProxy      *proxy);
00060 static void dbus_gproxy_emit_received (DBusGProxy      *proxy,
00061                                        DBusMessage     *message);
00062 
00063 
00068 typedef struct
00069 {
00070   GSList *proxies;
00071 
00072   char name[4]; 
00077 } DBusGProxyList;
00078 
00084 struct DBusGProxyManager
00085 {
00086   GStaticMutex lock; 
00087   int refcount;      
00088   DBusConnection *connection; 
00090   GHashTable *proxy_lists; 
00094 };
00095 
00096 static void              dbus_gproxy_manager_ref    (DBusGProxyManager *manager);
00097 static DBusHandlerResult dbus_gproxy_manager_filter (DBusConnection    *connection,
00098                                                      DBusMessage       *message,
00099                                                      void              *user_data);
00100 
00102 #define LOCK_MANAGER(mgr)   (g_static_mutex_lock (&(mgr)->lock))
00103 
00104 #define UNLOCK_MANAGER(mgr) (g_static_mutex_unlock (&(mgr)->lock))
00105 
00106 static int gproxy_manager_slot = -1;
00107 
00108 /* Lock controlling get/set manager as data on each connection */
00109 static GStaticMutex connection_gproxy_lock = G_STATIC_MUTEX_INIT;
00110 
00111 static DBusGProxyManager*
00112 dbus_gproxy_manager_get (DBusConnection *connection)
00113 {
00114   DBusGProxyManager *manager;
00115 
00116   dbus_connection_allocate_data_slot (&gproxy_manager_slot);
00117   if (gproxy_manager_slot < 0)
00118     g_error ("out of memory");
00119   
00120   g_static_mutex_lock (&connection_gproxy_lock);
00121   
00122   manager = dbus_connection_get_data (connection, gproxy_manager_slot);
00123   if (manager != NULL)
00124     {
00125       dbus_connection_free_data_slot (&gproxy_manager_slot);
00126       dbus_gproxy_manager_ref (manager);
00127       g_static_mutex_unlock (&connection_gproxy_lock);
00128       return manager;
00129     }
00130   
00131   manager = g_new0 (DBusGProxyManager, 1);
00132 
00133   manager->refcount = 1;
00134   manager->connection = connection;
00135   
00136   g_static_mutex_init (&manager->lock);
00137 
00138   /* Proxy managers keep the connection alive, which means that
00139    * DBusGProxy indirectly does. To free a connection you have to free
00140    * all the proxies referring to it.
00141    */
00142   dbus_connection_ref (manager->connection);
00143 
00144   dbus_connection_set_data (connection, gproxy_manager_slot,
00145                             manager, NULL);
00146 
00147   dbus_connection_add_filter (connection, dbus_gproxy_manager_filter,
00148                               manager, NULL);
00149   
00150   g_static_mutex_unlock (&connection_gproxy_lock);
00151   
00152   return manager;
00153 }
00154 
00155 static void
00156 dbus_gproxy_manager_ref (DBusGProxyManager *manager)
00157 {
00158   g_assert (manager != NULL);
00159   g_assert (manager->refcount > 0);
00160 
00161   LOCK_MANAGER (manager);
00162   
00163   manager->refcount += 1;
00164 
00165   UNLOCK_MANAGER (manager);
00166 }
00167 
00168 static void
00169 dbus_gproxy_manager_unref (DBusGProxyManager *manager)
00170 {
00171   g_assert (manager != NULL);
00172   g_assert (manager->refcount > 0);
00173 
00174   LOCK_MANAGER (manager);
00175   manager->refcount -= 1;
00176   if (manager->refcount == 0)
00177     {
00178       UNLOCK_MANAGER (manager);
00179 
00180       if (manager->proxy_lists)
00181         {
00182           /* can't have any proxies left since they hold
00183            * a reference to the proxy manager.
00184            */
00185           g_assert (g_hash_table_size (manager->proxy_lists) == 0);
00186           
00187           g_hash_table_destroy (manager->proxy_lists);
00188           manager->proxy_lists = NULL;
00189         }
00190       
00191       g_static_mutex_free (&manager->lock);
00192 
00193       g_static_mutex_lock (&connection_gproxy_lock);
00194 
00195       dbus_connection_remove_filter (manager->connection, dbus_gproxy_manager_filter,
00196                                      manager);
00197       
00198       dbus_connection_set_data (manager->connection,
00199                                 gproxy_manager_slot,
00200                                 NULL, NULL);
00201 
00202       g_static_mutex_unlock (&connection_gproxy_lock);
00203       
00204       dbus_connection_unref (manager->connection);
00205       g_free (manager);
00206 
00207       dbus_connection_free_data_slot (&gproxy_manager_slot);
00208     }
00209   else
00210     {
00211       UNLOCK_MANAGER (manager);
00212     }
00213 }
00214 
00215 static guint
00216 tristring_hash (gconstpointer key)
00217 {
00218   const char *p = key;
00219   guint h = *p;
00220 
00221   if (h)
00222     {
00223       for (p += 1; *p != '\0'; p++)
00224         h = (h << 5) - h + *p;
00225     }
00226 
00227   /* skip nul and do the next substring */
00228   for (p += 1; *p != '\0'; p++)
00229     h = (h << 5) - h + *p;
00230 
00231   /* skip nul again and another substring */
00232   for (p += 1; *p != '\0'; p++)
00233     h = (h << 5) - h + *p;
00234   
00235   return h;
00236 }
00237 
00238 static gboolean
00239 strequal_len (const char *a,
00240               const char *b,
00241               size_t     *lenp)
00242 {
00243   size_t a_len;
00244   size_t b_len;
00245 
00246   a_len = strlen (a);
00247   b_len = strlen (b);
00248 
00249   if (a_len != b_len)
00250     return FALSE;
00251 
00252   if (memcmp (a, b, a_len) != 0)
00253     return FALSE;
00254   
00255   *lenp = a_len;
00256 
00257   return TRUE;
00258 }
00259 
00260 static gboolean
00261 tristring_equal (gconstpointer  a,
00262                  gconstpointer  b)
00263 {
00264   const char *ap = a;
00265   const char *bp = b;
00266   size_t len;
00267 
00268   if (!strequal_len (ap, bp, &len))
00269     return FALSE;
00270 
00271   ap += len + 1;
00272   bp += len + 1;
00273 
00274   if (!strequal_len (ap, bp, &len))
00275     return FALSE;
00276 
00277   ap += len + 1;
00278   bp += len + 1;
00279 
00280   if (strcmp (ap, bp) != 0)
00281     return FALSE;
00282   
00283   return TRUE;
00284 }
00285 
00286 static char*
00287 tristring_alloc_from_strings (size_t      padding_before,
00288                               const char *service,
00289                               const char *path,
00290                               const char *interface)
00291 {
00292   size_t service_len, iface_len, path_len, len;
00293   char *tri;
00294   
00295   if (service)
00296     service_len = strlen (service);
00297   else
00298     service_len = 0;
00299 
00300   path_len = strlen (path);
00301   
00302   iface_len = strlen (interface);
00303 
00304   tri = g_malloc (padding_before + service_len + path_len + iface_len + 3);
00305 
00306   len = padding_before;
00307   
00308   if (service)
00309     memcpy (&tri[len], service, service_len);
00310 
00311   len += service_len;
00312   tri[len] = '\0';
00313   len += 1;
00314 
00315   g_assert (len == (padding_before + service_len + 1));
00316   
00317   memcpy (&tri[len], path, path_len);
00318   len += path_len;
00319   tri[len] = '\0';
00320   len += 1;
00321 
00322   g_assert (len == (padding_before + service_len + path_len + 2));
00323   
00324   memcpy (&tri[len], interface, iface_len);
00325   len += iface_len;
00326   tri[len] = '\0';
00327   len += 1;
00328 
00329   g_assert (len == (padding_before + service_len + path_len + iface_len + 3));
00330 
00331   return tri;
00332 }
00333 
00334 static char*
00335 tristring_from_proxy (DBusGProxy *proxy)
00336 {
00337   return tristring_alloc_from_strings (0,
00338                                        proxy->service,
00339                                        proxy->path,
00340                                        proxy->interface);
00341 }
00342 
00343 static char*
00344 tristring_from_message (DBusMessage *message)
00345 {
00346   return tristring_alloc_from_strings (0,
00347                                        dbus_message_get_sender (message),
00348                                        dbus_message_get_path (message),
00349                                        dbus_message_get_interface (message));
00350 }
00351 
00352 static DBusGProxyList*
00353 gproxy_list_new (DBusGProxy *first_proxy)
00354 {
00355   DBusGProxyList *list;
00356   
00357   list = (void*) tristring_alloc_from_strings (G_STRUCT_OFFSET (DBusGProxyList, name),
00358                                                first_proxy->service,
00359                                                first_proxy->path,
00360                                                first_proxy->interface);
00361   list->proxies = NULL;
00362 
00363   return list;
00364 }
00365 
00366 static void
00367 gproxy_list_free (DBusGProxyList *list)
00368 {
00369   /* we don't hold a reference to the proxies in the list,
00370    * as they ref the GProxyManager
00371    */
00372   g_slist_free (list->proxies);  
00373 
00374   g_free (list);
00375 }
00376 
00377 static char*
00378 gproxy_get_match_rule (DBusGProxy *proxy)
00379 {
00380   /* FIXME Escaping is required here */
00381   
00382   if (proxy->service)
00383     return g_strdup_printf ("type='signal',sender='%s',path='%s',interface='%s'",
00384                             proxy->service, proxy->path, proxy->interface);
00385   else
00386     return g_strdup_printf ("type='signal',path='%s',interface='%s'",
00387                             proxy->path, proxy->interface);
00388 }
00389 
00390 static void
00391 dbus_gproxy_manager_register (DBusGProxyManager *manager,
00392                               DBusGProxy        *proxy)
00393 {
00394   DBusGProxyList *list;
00395 
00396   LOCK_MANAGER (manager);
00397 
00398   if (manager->proxy_lists == NULL)
00399     {
00400       list = NULL;
00401       manager->proxy_lists = g_hash_table_new_full (tristring_hash,
00402                                                     tristring_equal,
00403                                                     NULL,
00404                                                     (GFreeFunc) gproxy_list_free);
00405     }
00406   else
00407     {
00408       char *tri;
00409 
00410       tri = tristring_from_proxy (proxy);
00411       
00412       list = g_hash_table_lookup (manager->proxy_lists, tri);
00413 
00414       g_free (tri);
00415     }
00416       
00417   if (list == NULL)
00418     {
00419       list = gproxy_list_new (proxy);
00420       
00421       g_hash_table_replace (manager->proxy_lists,
00422                             list->name, list);
00423     }
00424 
00425   if (list->proxies == NULL)
00426     {
00427       /* We have to add the match rule to the server,
00428        * but FIXME only if the server is a message bus,
00429        * not if it's a peer.
00430        */
00431       char *rule;
00432 
00433       rule = gproxy_get_match_rule (proxy);
00434       
00435       /* We don't check for errors; it's not like anyone would handle them,
00436        * and we don't want a round trip here.
00437        */
00438       dbus_bus_add_match (manager->connection,
00439                           rule, NULL);
00440 
00441       g_free (rule);
00442     }
00443 
00444   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00445   
00446   list->proxies = g_slist_prepend (list->proxies, proxy);
00447   
00448   UNLOCK_MANAGER (manager);
00449 }
00450 
00451 static void
00452 dbus_gproxy_manager_unregister (DBusGProxyManager *manager,
00453                                 DBusGProxy        *proxy)
00454 {
00455   DBusGProxyList *list;
00456   char *tri;
00457   
00458   LOCK_MANAGER (manager);
00459 
00460 #ifndef G_DISABLE_CHECKS
00461   if (manager->proxy_lists == NULL)
00462     {
00463       g_warning ("Trying to unregister a proxy but there aren't any registered");
00464       return;
00465     }
00466 #endif
00467 
00468   tri = tristring_from_proxy (proxy);
00469   
00470   list = g_hash_table_lookup (manager->proxy_lists, tri);
00471 
00472 #ifndef G_DISABLE_CHECKS
00473   if (list == NULL)
00474     {
00475       g_warning ("Trying to unregister a proxy but it isn't registered");
00476       return;
00477     }
00478 #endif
00479 
00480   g_assert (g_slist_find (list->proxies, proxy) != NULL);
00481   
00482   list->proxies = g_slist_remove (list->proxies, proxy);
00483 
00484   g_assert (g_slist_find (list->proxies, proxy) == NULL);
00485 
00486   if (list->proxies == NULL)
00487     {
00488       g_hash_table_remove (manager->proxy_lists,
00489                            tri);
00490       list = NULL;
00491     }
00492   
00493   if (g_hash_table_size (manager->proxy_lists) == 0)
00494     {
00495       g_hash_table_destroy (manager->proxy_lists);
00496       manager->proxy_lists = NULL;
00497     }
00498 
00499   g_free (tri);
00500       
00501   UNLOCK_MANAGER (manager);
00502 }
00503 
00504 static void
00505 list_proxies_foreach (gpointer key,
00506                       gpointer value,
00507                       gpointer user_data)
00508 {
00509   DBusGProxyList *list;
00510   GSList **ret;
00511   GSList *tmp;
00512   
00513   list = value;
00514   ret = user_data;
00515 
00516   tmp = list->proxies;
00517   while (tmp != NULL)
00518     {
00519       DBusGProxy *proxy = DBUS_GPROXY (tmp->data);
00520 
00521       g_object_ref (proxy);
00522       *ret = g_slist_prepend (*ret, proxy);
00523       
00524       tmp = tmp->next;
00525     }
00526 }
00527 
00528 static GSList*
00529 dbus_gproxy_manager_list_all (DBusGProxyManager *manager)
00530 {
00531   GSList *ret;
00532 
00533   ret = NULL;
00534 
00535   if (manager->proxy_lists)
00536     {
00537       g_hash_table_foreach (manager->proxy_lists,
00538                             list_proxies_foreach,
00539                             &ret);
00540     }
00541 
00542   return ret;
00543 }
00544 
00545 static DBusHandlerResult
00546 dbus_gproxy_manager_filter (DBusConnection    *connection,
00547                             DBusMessage       *message,
00548                             void              *user_data)
00549 {
00550   DBusGProxyManager *manager;
00551   
00552   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_SIGNAL)
00553     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00554 
00555   manager = user_data;
00556 
00557   dbus_gproxy_manager_ref (manager);
00558   
00559   LOCK_MANAGER (manager);
00560   
00561   if (dbus_message_is_signal (message,
00562                               DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL,
00563                               "Disconnected"))
00564     {
00565       /* Destroy all the proxies, quite possibly resulting in unreferencing
00566        * the proxy manager and the connection as well.
00567        */
00568       GSList *all;
00569       GSList *tmp;
00570 
00571       all = dbus_gproxy_manager_list_all (manager);
00572 
00573       tmp = all;
00574       while (tmp != NULL)
00575         {
00576           DBusGProxy *proxy;
00577 
00578           proxy = DBUS_GPROXY (tmp->data);
00579 
00580           UNLOCK_MANAGER (manager);
00581           dbus_gproxy_destroy (proxy);
00582           g_object_unref (G_OBJECT (proxy));
00583           LOCK_MANAGER (manager);
00584           
00585           tmp = tmp->next;
00586         }
00587 
00588       g_slist_free (all);
00589 
00590 #ifndef G_DISABLE_CHECKS
00591       if (manager->proxy_lists != NULL)
00592         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.");
00593 #endif
00594     }
00595   else
00596     {
00597       char *tri;
00598       DBusGProxyList *list;
00599       
00600       tri = tristring_from_message (message);
00601 
00602       if (manager->proxy_lists)
00603         list = g_hash_table_lookup (manager->proxy_lists, tri);
00604       else
00605         list = NULL;
00606 
00607 #if 0
00608       g_print ("proxy got %s,%s,%s = list %p\n",
00609                tri,
00610                tri + strlen (tri) + 1,
00611                tri + strlen (tri) + 1 + strlen (tri + strlen (tri) + 1) + 1,
00612                list);
00613 #endif
00614       
00615       g_free (tri);
00616 
00617       /* Emit the signal */
00618       
00619       if (list != NULL)
00620         {
00621           GSList *tmp;
00622           GSList *copy;
00623 
00624           copy = g_slist_copy (list->proxies);
00625           g_slist_foreach (copy, (GFunc) g_object_ref, NULL);
00626           
00627           tmp = copy;
00628           while (tmp != NULL)
00629             {
00630               DBusGProxy *proxy;
00631 
00632               proxy = DBUS_GPROXY (tmp->data);
00633 
00634               UNLOCK_MANAGER (manager);
00635               dbus_gproxy_emit_received (proxy, message);
00636               g_object_unref (G_OBJECT (proxy));
00637               LOCK_MANAGER (manager);
00638               
00639               tmp = tmp->next;
00640             }
00641 
00642           g_slist_free (copy);
00643         }
00644     }
00645 
00646   UNLOCK_MANAGER (manager);
00647   dbus_gproxy_manager_unref (manager);
00648   
00649   /* "Handling" signals doesn't make sense, they are for everyone
00650    * who cares
00651    */
00652   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00653 }
00654 
00655 
00656 
00657 /*      ---------- DBusGProxy --------------   */
00658 
00659 
00660 
00661 enum
00662 {
00663   DESTROY,
00664   RECEIVED,
00665   LAST_SIGNAL
00666 };
00667 
00668 static void *parent_class;
00669 static guint signals[LAST_SIGNAL] = { 0 };
00670 
00671 static void
00672 dbus_gproxy_init (DBusGProxy *proxy)
00673 {
00674   /* Nothing */
00675 }
00676 
00677 static void
00678 dbus_gproxy_class_init (DBusGProxyClass *klass)
00679 {
00680   GObjectClass *object_class = G_OBJECT_CLASS (klass);
00681   
00682   parent_class = g_type_class_peek_parent (klass);
00683   
00684   object_class->finalize = dbus_gproxy_finalize;
00685   object_class->dispose = dbus_gproxy_dispose;
00686   
00687   signals[DESTROY] =
00688     g_signal_new ("destroy",
00689                   G_OBJECT_CLASS_TYPE (object_class),
00690                   G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
00691                   0,
00692                   NULL, NULL,
00693                   g_cclosure_marshal_VOID__VOID,
00694                   G_TYPE_NONE, 0);
00695   
00696   signals[RECEIVED] =
00697     g_signal_new ("received",
00698                   G_OBJECT_CLASS_TYPE (object_class),
00699                   G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
00700                   0,
00701                   NULL, NULL,
00702                   g_cclosure_marshal_VOID__BOXED,
00703                   G_TYPE_NONE, 1,
00704                   DBUS_TYPE_MESSAGE);
00705 }
00706 
00707 
00708 static void
00709 dbus_gproxy_dispose (GObject *object)
00710 {
00711   DBusGProxy *proxy;
00712 
00713   proxy = DBUS_GPROXY (object);
00714 
00715   g_signal_emit (object, signals[DESTROY], 0);
00716   
00717   G_OBJECT_CLASS (parent_class)->dispose (object);
00718 }
00719 
00720 static void
00721 dbus_gproxy_finalize (GObject *object)
00722 {
00723   DBusGProxy *proxy;
00724 
00725   proxy = DBUS_GPROXY (object);
00726 
00727   if (proxy->manager)
00728     {
00729       dbus_gproxy_manager_unregister (proxy->manager, proxy);
00730       dbus_gproxy_manager_unref (proxy->manager);
00731     }
00732   
00733   g_free (proxy->service);
00734   g_free (proxy->path);
00735   g_free (proxy->interface);
00736   
00737   G_OBJECT_CLASS (parent_class)->finalize (object);
00738 }
00739 
00740 static void
00741 dbus_gproxy_destroy (DBusGProxy *proxy)
00742 {
00743   /* FIXME do we need the GTK_IN_DESTRUCTION style flag
00744    * from GtkObject?
00745    */
00746   g_object_run_dispose (G_OBJECT (proxy));
00747 }
00748 
00749 static char*
00750 create_signal_detail (const char *interface,
00751                       const char *signal)
00752 {
00753   GString *str;
00754 
00755   str = g_string_new (interface);
00756 
00757   g_string_append (str, ".");
00758 
00759   g_string_append (str, signal);
00760 
00761   return g_string_free (str, FALSE);
00762 }
00763 
00764 static void
00765 dbus_gproxy_emit_received (DBusGProxy  *proxy,
00766                            DBusMessage *message)
00767 {
00768   const char *interface;
00769   const char *signal;
00770   char *detail;
00771   GQuark q;
00772   
00773   interface = dbus_message_get_interface (message);
00774   signal = dbus_message_get_member (message);
00775 
00776   g_assert (interface != NULL);
00777   g_assert (signal != NULL);
00778 
00779   detail = create_signal_detail (interface, signal);
00780 
00781   /* If the quark isn't preexisting, there's no way there
00782    * are any handlers connected. We don't want to create
00783    * extra quarks for every possible signal.
00784    */
00785   q = g_quark_try_string (detail);
00786 
00787   if (q != 0)
00788     g_signal_emit (G_OBJECT (proxy),
00789                    signals[RECEIVED],
00790                    q,
00791                    message);
00792 
00793   g_free (detail);
00794 }
00795 
00807 GType
00808 dbus_gproxy_get_type (void)
00809 {
00810   static GType object_type = 0;
00811 
00812   if (!object_type)
00813     {
00814       static const GTypeInfo object_info =
00815         {
00816           sizeof (DBusGProxyClass),
00817           (GBaseInitFunc) NULL,
00818           (GBaseFinalizeFunc) NULL,
00819           (GClassInitFunc) dbus_gproxy_class_init,
00820           NULL,           /* class_finalize */
00821           NULL,           /* class_data */
00822           sizeof (DBusGProxy),
00823           0,              /* n_preallocs */
00824           (GInstanceInitFunc) dbus_gproxy_init,
00825         };
00826       
00827       object_type = g_type_register_static (G_TYPE_OBJECT,
00828                                             "DBusGProxy",
00829                                             &object_info, 0);
00830     }
00831   
00832   return object_type;
00833 }
00834 
00835 static DBusGProxy*
00836 dbus_gproxy_new (DBusConnection *connection,
00837                  const char     *service_name,
00838                  const char     *path_name,
00839                  const char     *interface_name)
00840 {
00841   DBusGProxy *proxy;
00842 
00843   g_assert (connection != NULL);
00844   
00845   proxy = g_object_new (DBUS_TYPE_GPROXY, NULL);
00846 
00847   /* These should all be construct-only mandatory properties,
00848    * for now we just don't let people use g_object_new().
00849    */
00850   
00851   proxy->manager = dbus_gproxy_manager_get (connection);
00852   
00853   proxy->service = g_strdup (service_name);
00854   proxy->path = g_strdup (path_name);
00855   proxy->interface = g_strdup (interface_name);
00856 
00857   dbus_gproxy_manager_register (proxy->manager, proxy);
00858   
00859   return proxy;
00860 }
00861 
00884 DBusGProxy*
00885 dbus_gproxy_new_for_service (DBusConnection *connection,
00886                              const char     *service_name,
00887                              const char     *path_name,
00888                              const char     *interface_name)
00889 {
00890   DBusGProxy *proxy;
00891 
00892   g_return_val_if_fail (connection != NULL, NULL);
00893   g_return_val_if_fail (service_name != NULL, NULL);
00894   g_return_val_if_fail (path_name != NULL, NULL);
00895   g_return_val_if_fail (interface_name != NULL, NULL);
00896   
00897   proxy = dbus_gproxy_new (connection, service_name,
00898                            path_name, interface_name);
00899 
00900   return proxy;
00901 }
00902 
00926 DBusGProxy*
00927 dbus_gproxy_new_for_service_owner (DBusConnection           *connection,
00928                                    const char               *service_name,
00929                                    const char               *path_name,
00930                                    const char               *interface_name,
00931                                    GError                  **error)
00932 {
00933   g_return_val_if_fail (connection != NULL, NULL);
00934   g_return_val_if_fail (service_name != NULL, NULL);
00935   g_return_val_if_fail (path_name != NULL, NULL);
00936   g_return_val_if_fail (interface_name != NULL, NULL);
00937 
00938 
00939 }
00940 
00955 DBusGProxy*
00956 dbus_gproxy_new_for_peer (DBusConnection           *connection,
00957                           const char               *path_name,
00958                           const char               *interface_name)
00959 {
00960   DBusGProxy *proxy;
00961   
00962   g_return_val_if_fail (connection != NULL, NULL);
00963   g_return_val_if_fail (path_name != NULL, NULL);
00964   g_return_val_if_fail (interface_name != NULL, NULL);
00965 
00966   proxy = dbus_gproxy_new (connection, NULL,
00967                            path_name, interface_name);
00968 
00969   return proxy;
00970 }
00971 
00991 DBusPendingCall*
00992 dbus_gproxy_begin_call (DBusGProxy *proxy,
00993                         const char *method,
00994                         int         first_arg_type,
00995                         ...)
00996 {
00997   DBusPendingCall *pending;
00998   DBusMessage *message;
00999   va_list args;
01000   
01001   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), NULL);
01002 
01003   message = dbus_message_new_method_call (proxy->service,
01004                                           proxy->path,
01005                                           proxy->interface,
01006                                           method);
01007   if (message == NULL)
01008     goto oom;
01009 
01010   va_start (args, first_arg_type);
01011   if (!dbus_message_append_args_valist (message, first_arg_type,
01012                                         args))
01013     goto oom;
01014   va_end (args);
01015 
01016   if (!dbus_connection_send_with_reply (proxy->manager->connection,
01017                                         message,
01018                                         &pending,
01019                                         -1))
01020     goto oom;
01021 
01022   return pending;
01023 
01024  oom:
01025   /* FIXME we should create a pending call that's
01026    * immediately completed with an error status without
01027    * ever going on the wire.
01028    */
01029   
01030   g_error ("Out of memory");
01031   return NULL;
01032 }
01033 
01059 gboolean
01060 dbus_gproxy_end_call (DBusGProxy          *proxy,
01061                       DBusPendingCall     *pending,
01062                       GError             **error,
01063                       int                  first_arg_type,
01064                       ...)
01065 {
01066   DBusMessage *message;
01067   va_list args;
01068   DBusError derror;
01069   
01070   g_return_val_if_fail (DBUS_IS_GPROXY (proxy), FALSE);
01071   g_return_val_if_fail (pending != NULL, FALSE);
01072 
01073   dbus_pending_call_block (pending);
01074   message = dbus_pending_call_get_reply (pending);
01075 
01076   g_assert (message != NULL);
01077 
01078   dbus_error_init (&derror);
01079 
01080   switch (dbus_message_get_type (message))
01081     {
01082     case DBUS_MESSAGE_TYPE_METHOD_RETURN:
01083       va_start (args, first_arg_type);
01084       if (!dbus_message_get_args_valist (message, &derror, first_arg_type, args))
01085         {
01086           va_end (args);
01087           goto error;
01088         }
01089       va_end (args);
01090 
01091       return TRUE;
01092       
01093     case DBUS_MESSAGE_TYPE_ERROR:
01094       dbus_set_error_from_message (&derror, message);
01095       goto error;
01096 
01097     default:
01098       dbus_set_error (&derror, DBUS_ERROR_FAILED,
01099                       "Reply was neither a method return nor an exception");
01100       goto error;
01101     }
01102 
01103  error:
01104   dbus_set_g_error (error, &derror);
01105   dbus_error_free (&derror);
01106   return FALSE;
01107 }
01108 
01120 void
01121 dbus_gproxy_call_no_reply (DBusGProxy               *proxy,
01122                            const char               *method,
01123                            int                       first_arg_type,
01124                            ...)
01125 {
01126   DBusMessage *message;
01127   va_list args;
01128   
01129   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01130 
01131   message = dbus_message_new_method_call (proxy->service,
01132                                           proxy->path,
01133                                           proxy->interface,
01134                                           method);
01135   if (message == NULL)
01136     goto oom;
01137 
01138   dbus_message_set_no_reply (message, TRUE);
01139   
01140   va_start (args, first_arg_type);
01141   if (!dbus_message_append_args_valist (message, first_arg_type,
01142                                         args)) {
01143     va_end (args);
01144     goto oom;
01145   }
01146   va_end (args);
01147 
01148   if (!dbus_connection_send (proxy->manager->connection,
01149                              message,
01150                              NULL))
01151     goto oom;
01152 
01153   return;
01154   
01155  oom:
01156   g_error ("Out of memory");
01157 }
01158 
01177 void
01178 dbus_gproxy_send (DBusGProxy          *proxy,
01179                   DBusMessage         *message,
01180                   dbus_uint32_t       *client_serial)
01181 {
01182   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01183   
01184   if (proxy->service)
01185     {
01186       if (!dbus_message_set_destination (message, proxy->service))
01187         g_error ("Out of memory");
01188     }
01189   if (proxy->path)
01190     {
01191       if (!dbus_message_set_path (message, proxy->path))
01192         g_error ("Out of memory");
01193     }
01194   if (proxy->interface)
01195     {
01196       if (!dbus_message_set_interface (message, proxy->interface))
01197         g_error ("Out of memory");
01198     }
01199   
01200   if (!dbus_connection_send (proxy->manager->connection, message, client_serial))
01201     g_error ("Out of memory\n");
01202 }
01203 
01204 void
01205 dbus_gproxy_connect_signal (DBusGProxy             *proxy,
01206                             const char             *signal_name,
01207                             DBusGProxySignalHandler handler,
01208                             void                   *data,
01209                             GClosureNotify          free_data_func)
01210 {
01211   GClosure *closure;
01212   char *detail;
01213 
01214   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01215   g_return_if_fail (signal_name != NULL);
01216   g_return_if_fail (handler != NULL);
01217   
01218   detail = create_signal_detail (proxy->interface, signal_name);
01219   
01220   closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
01221   g_signal_connect_closure_by_id (G_OBJECT (proxy),
01222                                   signals[RECEIVED],
01223                                   g_quark_from_string (detail),
01224                                   closure, FALSE);
01225 
01226   g_free (detail);
01227 }
01228 
01229 void
01230 dbus_gproxy_disconnect_signal (DBusGProxy             *proxy,
01231                                const char             *signal_name,
01232                                DBusGProxySignalHandler handler,
01233                                void                   *data)
01234 {
01235   char *detail;
01236   GQuark q;
01237   
01238   g_return_if_fail (DBUS_IS_GPROXY (proxy));
01239   g_return_if_fail (signal_name != NULL);
01240   g_return_if_fail (handler != NULL);
01241 
01242   detail = create_signal_detail (proxy->interface, signal_name);
01243   q = g_quark_try_string (detail);
01244   g_free (detail);
01245 
01246 #ifndef G_DISABLE_CHECKS
01247   if (q == 0)
01248     {
01249       g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
01250                  G_GNUC_FUNCTION, signal_name);
01251       return;
01252     }
01253 #endif
01254 
01255   g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
01256                                         G_SIGNAL_MATCH_DETAIL |
01257                                         G_SIGNAL_MATCH_FUNC   |
01258                                         G_SIGNAL_MATCH_DATA,
01259                                         signals[RECEIVED],
01260                                         q,
01261                                         NULL,
01262                                         G_CALLBACK (handler), data);
01263 }
01264 
01267 #ifdef DBUS_BUILD_TESTS
01268 
01274 dbus_bool_t
01275 _dbus_gproxy_test (void)
01276 {
01277   
01278   
01279   return TRUE;
01280 }
01281 
01282 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Feb 10 18:14:03 2004 for D-BUS by doxygen 1.3.5