Main Page   Modules   Data Structures   File List   Data Fields   Related Pages  

dbus-bus.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-bus.c  Convenience functions for communicating with the bus.
00003  *
00004  * Copyright (C) 2003  CodeFactory AB
00005  * Copyright (C) 2003  Red Hat, Inc.
00006  *
00007  * Licensed under the Academic Free License version 1.2
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "dbus-bus.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-internals.h"
00028 #include <string.h>
00029 
00056 typedef struct
00057 {
00058   DBusConnection *connection; 
00059   char *base_service; 
00061   unsigned int is_well_known : 1; 
00062 } BusData;
00063 
00066 static dbus_int32_t bus_data_slot = -1;
00067 
00069 #define N_BUS_TYPES 3
00070 
00071 static DBusConnection *bus_connections[N_BUS_TYPES];
00072 static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL };
00073 
00074 static DBusBusType activation_bus_type = DBUS_BUS_ACTIVATION;
00075 
00076 static dbus_bool_t initialized = FALSE;
00077 
00081 _DBUS_DEFINE_GLOBAL_LOCK (bus);
00082 
00083 static void
00084 addresses_shutdown_func (void *data)
00085 {
00086   int i;
00087 
00088   i = 0;
00089   while (i < N_BUS_TYPES)
00090     {
00091       if (bus_connections[i] != NULL)
00092         _dbus_warn ("dbus_shutdown() called but connections were still live!");
00093       
00094       dbus_free (bus_connection_addresses[i]);
00095       bus_connection_addresses[i] = NULL;
00096       ++i;
00097     }
00098 
00099   activation_bus_type = DBUS_BUS_ACTIVATION;
00100 }
00101 
00102 static dbus_bool_t
00103 get_from_env (char           **connection_p,
00104               const char      *env_var)
00105 {
00106   const char *s;
00107   
00108   _dbus_assert (*connection_p == NULL);
00109   
00110   s = _dbus_getenv (env_var);
00111   if (s == NULL || *s == '\0')
00112     return TRUE; /* successfully didn't use the env var */
00113   else
00114     {
00115       *connection_p = _dbus_strdup (s);
00116       return *connection_p != NULL;
00117     }
00118 }
00119 
00120 static dbus_bool_t
00121 init_connections_unlocked (void)
00122 {
00123   if (!initialized)
00124     {
00125       const char *s;
00126       int i;
00127 
00128       i = 0;
00129       while (i < N_BUS_TYPES)
00130         {
00131           bus_connections[i] = NULL;
00132           ++i;
00133         }
00134 
00135       /* Don't init these twice, we may run this code twice if
00136        * init_connections_unlocked() fails midway through.
00137        */
00138       
00139        if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
00140          {
00141            if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM],
00142                               "DBUS_SYSTEM_BUS_ADDRESS"))
00143              return FALSE;
00144            
00145            if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
00146              {
00147                /* Use default system bus address if none set in environment */
00148                bus_connection_addresses[DBUS_BUS_SYSTEM] =
00149                  _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
00150                if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
00151                  return FALSE;
00152              }
00153          }
00154           
00155       if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
00156         {
00157           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
00158                              "DBUS_SESSION_BUS_ADDRESS"))
00159             return FALSE;
00160         }
00161 
00162       if (bus_connection_addresses[DBUS_BUS_ACTIVATION] == NULL)
00163         {
00164           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_ACTIVATION],
00165                              "DBUS_ACTIVATION_ADDRESS"))
00166             return FALSE;
00167         }
00168 
00169       s = _dbus_getenv ("DBUS_ACTIVATION_BUS_TYPE");
00170 
00171       if (s != NULL)
00172         {
00173           if (strcmp (s, "system") == 0)
00174             activation_bus_type = DBUS_BUS_SYSTEM;
00175           else if (strcmp (s, "session") == 0)
00176             activation_bus_type = DBUS_BUS_SESSION;
00177         }
00178 
00179       /* If we return FALSE we have to be sure that restarting
00180        * the above code will work right
00181        */
00182       
00183       if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL))
00184         return FALSE;
00185 
00186       if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL))
00187         return FALSE;
00188       
00189       if (!_dbus_register_shutdown_func (addresses_shutdown_func,
00190                                          NULL))
00191         return FALSE;
00192       
00193       initialized = TRUE;
00194     }
00195 
00196   return initialized;
00197 }
00198 
00199 static void
00200 bus_data_free (void *data)
00201 {
00202   BusData *bd = data;
00203   
00204   if (bd->is_well_known)
00205     {
00206       int i;
00207       _DBUS_LOCK (bus);
00208       /* We may be stored in more than one slot */
00209       i = 0;
00210       while (i < N_BUS_TYPES)
00211         {
00212           if (bus_connections[i] == bd->connection)
00213             bus_connections[i] = NULL;
00214           
00215           ++i;
00216         }
00217       _DBUS_UNLOCK (bus);
00218     }
00219   
00220   dbus_free (bd->base_service);
00221   dbus_free (bd);
00222 
00223   dbus_connection_free_data_slot (&bus_data_slot);
00224 }
00225 
00226 static BusData*
00227 ensure_bus_data (DBusConnection *connection)
00228 {
00229   BusData *bd;
00230 
00231   if (!dbus_connection_allocate_data_slot (&bus_data_slot))
00232     return NULL;
00233 
00234   bd = dbus_connection_get_data (connection, bus_data_slot);
00235   if (bd == NULL)
00236     {      
00237       bd = dbus_new0 (BusData, 1);
00238       if (bd == NULL)
00239         {
00240           dbus_connection_free_data_slot (&bus_data_slot);
00241           return NULL;
00242         }
00243 
00244       bd->connection = connection;
00245       
00246       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
00247                                      bus_data_free))
00248         {
00249           dbus_free (bd);
00250           dbus_connection_free_data_slot (&bus_data_slot);
00251           return NULL;
00252         }
00253 
00254       /* Data slot refcount now held by the BusData */
00255     }
00256   else
00257     {
00258       dbus_connection_free_data_slot (&bus_data_slot);
00259     }
00260 
00261   return bd;
00262 }
00263  /* end of implementation details docs */
00265 
00281 DBusConnection *
00282 dbus_bus_get (DBusBusType  type,
00283               DBusError   *error)
00284 {
00285   const char *address;
00286   DBusConnection *connection;
00287   BusData *bd;
00288   DBusBusType address_type;
00289 
00290   _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
00291   _dbus_return_val_if_error_is_set (error, NULL);
00292 
00293   _DBUS_LOCK (bus);
00294 
00295   if (!init_connections_unlocked ())
00296     {
00297       _DBUS_UNLOCK (bus);
00298       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00299       return NULL;
00300     }
00301 
00302   /* We want to use the activation address even if the
00303    * activating bus is the session or system bus,
00304    * per the spec.
00305    */
00306   address_type = type;
00307   
00308   /* Use the real type of the activation bus for getting its
00309    * connection. (If the activating bus isn't a well-known
00310    * bus then activation_bus_type == DBUS_BUS_ACTIVATION)
00311    */
00312   if (type == DBUS_BUS_ACTIVATION)
00313     type = activation_bus_type;
00314   
00315   if (bus_connections[type] != NULL)
00316     {
00317       connection = bus_connections[type];
00318       dbus_connection_ref (connection);
00319       
00320       _DBUS_UNLOCK (bus);
00321       return connection;
00322     }
00323 
00324   address = bus_connection_addresses[address_type];
00325   if (address == NULL)
00326     {
00327       dbus_set_error (error, DBUS_ERROR_FAILED,
00328                       "Unable to determine the address of the message bus");
00329       _DBUS_UNLOCK (bus);
00330       return NULL;
00331     }
00332 
00333   connection = dbus_connection_open (address, error);
00334   
00335   if (!connection)
00336     {
00337       _DBUS_ASSERT_ERROR_IS_SET (error);
00338       _DBUS_UNLOCK (bus);
00339       return NULL;
00340     }
00341   
00342   if (!dbus_bus_register (connection, error))
00343     {
00344       _DBUS_ASSERT_ERROR_IS_SET (error);
00345       dbus_connection_disconnect (connection);
00346       dbus_connection_unref (connection);
00347 
00348       _DBUS_UNLOCK (bus);
00349       return NULL;
00350     }
00351 
00352   bus_connections[type] = connection;
00353   bd = ensure_bus_data (connection);
00354   _dbus_assert (bd != NULL);
00355 
00356   bd->is_well_known = TRUE;
00357 
00358   _DBUS_UNLOCK (bus);
00359   return connection;
00360 }
00361 
00362 
00376 dbus_bool_t
00377 dbus_bus_register (DBusConnection *connection,
00378                    DBusError      *error)
00379 {
00380   DBusMessage *message, *reply;
00381   char *name;
00382   BusData *bd;
00383   dbus_bool_t retval;
00384 
00385   _dbus_return_val_if_fail (connection != NULL, FALSE);
00386   _dbus_return_val_if_error_is_set (error, FALSE);
00387 
00388   retval = FALSE;
00389   
00390   bd = ensure_bus_data (connection);
00391   if (bd == NULL)
00392     {
00393       _DBUS_SET_OOM (error);
00394       return FALSE;
00395     }
00396 
00397   if (bd->base_service != NULL)
00398     {
00399       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
00400       /* This isn't an error, it's a programming bug. We'll be nice
00401        * and not _dbus_assert_not_reached()
00402        */
00403       return TRUE;
00404     }
00405   
00406   message = dbus_message_new (DBUS_MESSAGE_HELLO,
00407                               DBUS_SERVICE_DBUS);
00408                               
00409 
00410   if (!message)
00411     {
00412       _DBUS_SET_OOM (error);
00413       return FALSE;
00414     }
00415   
00416   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
00417 
00418   dbus_message_unref (message);
00419   
00420   if (reply == NULL)
00421     goto out;
00422   else if (dbus_set_error_from_message (error, reply))
00423     goto out;
00424   else if (!dbus_message_get_args (reply, error,
00425                                    DBUS_TYPE_STRING, &name,
00426                                    DBUS_TYPE_INVALID))
00427     goto out;
00428   
00429   bd->base_service = name;
00430 
00431   retval = TRUE;
00432   
00433  out:
00434   if (reply)
00435     dbus_message_unref (reply);
00436 
00437   if (!retval)
00438     _DBUS_ASSERT_ERROR_IS_SET (error);
00439   
00440   return retval;
00441 }
00442 
00443 
00455 dbus_bool_t
00456 dbus_bus_set_base_service (DBusConnection *connection,
00457                            const char     *base_service)
00458 {
00459   BusData *bd;
00460 
00461   _dbus_return_val_if_fail (connection != NULL, FALSE);
00462   _dbus_return_val_if_fail (base_service != NULL, FALSE);
00463   
00464   bd = ensure_bus_data (connection);
00465   if (bd == NULL)
00466     return FALSE;
00467 
00468   _dbus_assert (bd->base_service == NULL);
00469   
00470   bd->base_service = _dbus_strdup (base_service);
00471   return bd->base_service != NULL;
00472 }
00473 
00482 const char*
00483 dbus_bus_get_base_service (DBusConnection *connection)
00484 {
00485   BusData *bd;
00486 
00487   _dbus_return_val_if_fail (connection != NULL, NULL);
00488   
00489   bd = ensure_bus_data (connection);
00490   if (bd == NULL)
00491     return NULL;
00492   
00493   return bd->base_service;
00494 }
00495 
00511 int
00512 dbus_bus_acquire_service (DBusConnection *connection,
00513                           const char     *service_name,
00514                           unsigned int    flags,
00515                           DBusError      *error)
00516 {
00517   DBusMessage *message, *reply;
00518   dbus_uint32_t service_result;
00519 
00520   _dbus_return_val_if_fail (connection != NULL, 0);
00521   _dbus_return_val_if_fail (service_name != NULL, 0);
00522   _dbus_return_val_if_error_is_set (error, 0);
00523   
00524   message = dbus_message_new (DBUS_MESSAGE_ACQUIRE_SERVICE,
00525                               DBUS_SERVICE_DBUS);
00526 
00527 
00528   if (message == NULL)
00529     {
00530       _DBUS_SET_OOM (error);
00531       return -1;
00532     }
00533  
00534   if (!dbus_message_append_args (message,
00535                                  DBUS_TYPE_STRING, service_name,
00536                                  DBUS_TYPE_UINT32, flags,
00537                                  DBUS_TYPE_INVALID))
00538     {
00539       dbus_message_unref (message);
00540       _DBUS_SET_OOM (error);
00541       return -1;
00542     }
00543   
00544   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
00545                                                      error);
00546   
00547   dbus_message_unref (message);
00548   
00549   if (reply == NULL)
00550     {
00551       _DBUS_ASSERT_ERROR_IS_SET (error);
00552       return -1;
00553     }  
00554 
00555   if (dbus_set_error_from_message (error, reply))
00556     {
00557       _DBUS_ASSERT_ERROR_IS_SET (error);
00558       dbus_message_unref (reply);
00559       return -1;
00560     }
00561   
00562   if (!dbus_message_get_args (reply, error,
00563                               DBUS_TYPE_UINT32, &service_result,
00564                               DBUS_TYPE_INVALID))
00565     {
00566       _DBUS_ASSERT_ERROR_IS_SET (error);
00567       dbus_message_unref (reply);
00568       return -1;
00569     }
00570 
00571   dbus_message_unref (reply);
00572   
00573   return service_result;
00574 }
00575 
00586 dbus_bool_t
00587 dbus_bus_service_exists (DBusConnection *connection,
00588                          const char     *service_name,
00589                          DBusError      *error)
00590 {
00591   DBusMessage *message, *reply;
00592   unsigned int exists;
00593 
00594   _dbus_return_val_if_fail (connection != NULL, FALSE);
00595   _dbus_return_val_if_fail (service_name != NULL, FALSE);
00596   _dbus_return_val_if_error_is_set (error, FALSE);
00597   
00598   message = dbus_message_new (DBUS_MESSAGE_SERVICE_EXISTS,
00599                               DBUS_SERVICE_DBUS);
00600   if (message == NULL)
00601     {
00602       _DBUS_SET_OOM (error);
00603       return FALSE;
00604     }
00605   
00606   if (!dbus_message_append_args (message,
00607                                  DBUS_TYPE_STRING, service_name,
00608                                  DBUS_TYPE_INVALID))
00609     {
00610       dbus_message_unref (message);
00611       _DBUS_SET_OOM (error);
00612       return FALSE;
00613     }
00614   
00615   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
00616   dbus_message_unref (message);
00617 
00618   if (reply == NULL)
00619     {
00620       _DBUS_ASSERT_ERROR_IS_SET (error);
00621       return FALSE;
00622     }
00623 
00624   if (!dbus_message_get_args (reply, error,
00625                               DBUS_TYPE_UINT32, &exists,
00626                               DBUS_TYPE_INVALID))
00627     {
00628       _DBUS_ASSERT_ERROR_IS_SET (error);
00629       return FALSE;
00630     }
00631   
00632   return (exists != FALSE);
00633 }
00634 
00650 dbus_bool_t
00651 dbus_bus_activate_service (DBusConnection *connection,
00652                            const char     *service_name,
00653                            dbus_uint32_t   flags,
00654                            dbus_uint32_t  *result,
00655                            DBusError      *error)
00656 {
00657   DBusMessage *msg;
00658   DBusMessage *reply;
00659 
00660   msg = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE,
00661                           DBUS_SERVICE_DBUS);
00662 
00663   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
00664                                  DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
00665     {
00666       dbus_message_unref (msg);
00667       _DBUS_SET_OOM (error);
00668       return FALSE;
00669     }
00670 
00671   reply = dbus_connection_send_with_reply_and_block (connection, msg,
00672                                                          -1, error);
00673   dbus_message_unref (msg);
00674 
00675   if (reply == NULL)
00676     {
00677       _DBUS_ASSERT_ERROR_IS_SET (error);
00678       return FALSE;
00679     }
00680 
00681   if (dbus_set_error_from_message (error, reply))
00682     {
00683       _DBUS_ASSERT_ERROR_IS_SET (error);
00684       dbus_message_unref (reply);
00685       return FALSE;
00686     }
00687 
00688   if (result != NULL &&
00689       !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
00690                               result, DBUS_TYPE_INVALID))
00691     {
00692       _DBUS_ASSERT_ERROR_IS_SET (error);
00693       dbus_message_unref (reply);
00694       return FALSE;
00695     }
00696   
00697   dbus_message_unref (reply);
00698   return TRUE;
00699 }
00700 
00701 

Generated on Wed Oct 22 14:05:01 2003 for D-BUS by doxygen1.3-rc3