2003-04-22 Havoc Pennington <hp@redhat.com>
[platform/upstream/dbus.git] / dbus / dbus-bus.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-bus.c  Convenience functions for communicating with the bus.
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  * Copyright (C) 2003  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 1.2
8  * 
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  * 
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-bus.h"
26 #include "dbus-protocol.h"
27 #include "dbus-internals.h"
28 #include <string.h>
29
30 /**
31  * @defgroup DBusBus Message bus APIs
32  * @ingroup DBus
33  * @brief Functions for communicating with the message bus
34  *
35  */
36
37
38 /**
39  * @defgroup DBusBusInternals Message bus APIs internals
40  * @ingroup DBusInternals
41  * @brief Internals of functions for communicating with the message bus
42  *
43  * @{
44  */
45
46 /**
47  * Block of message-bus-related data we attach to each
48  * #DBusConnection used with these convenience functions.
49  *
50  */
51 typedef struct
52 {
53   DBusConnection *connection; /**< Connection we're associated with */
54   char *base_service; /**< Base service name of this connection */
55
56   unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */
57 } BusData;
58
59 /** The slot we have reserved to store BusData
60  */
61 static int bus_data_slot = -1;
62 /** Number of connections using the slot
63  */
64 static int bus_data_slot_refcount = 0;
65
66 /** Number of bus types */
67 #define N_BUS_TYPES 3
68
69 static DBusConnection *bus_connections[N_BUS_TYPES];
70 static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL };
71
72 static DBusBusType activation_bus_type = DBUS_BUS_ACTIVATION;
73
74 static dbus_bool_t initialized = FALSE;
75
76 /**
77  * Lock for globals in this file
78  */
79 _DBUS_DEFINE_GLOBAL_LOCK (bus);
80
81 static void
82 addresses_shutdown_func (void *data)
83 {
84   int i;
85
86   i = 0;
87   while (i < N_BUS_TYPES)
88     {
89       if (bus_connections[i] != NULL)
90         _dbus_warn ("dbus_shutdown() called but connections were still live!");
91       
92       dbus_free (bus_connection_addresses[i]);
93       bus_connection_addresses[i] = NULL;
94       ++i;
95     }
96
97   activation_bus_type = DBUS_BUS_ACTIVATION;
98 }
99
100 static dbus_bool_t
101 get_from_env (char           **connection_p,
102               const char      *env_var)
103 {
104   const char *s;
105   
106   _dbus_assert (*connection_p == NULL);
107   
108   s = _dbus_getenv (env_var);
109   if (s == NULL || *s == '\0')
110     return TRUE; /* successfully didn't use the env var */
111   else
112     {
113       *connection_p = _dbus_strdup (s);
114       return *connection_p != NULL;
115     }
116 }
117
118 static dbus_bool_t
119 init_connections_unlocked (void)
120 {
121   if (!initialized)
122     {
123       const char *s;
124       int i;
125
126       i = 0;
127       while (i < N_BUS_TYPES)
128         {
129           bus_connections[i] = NULL;
130           ++i;
131         }
132
133       /* Don't init these twice, we may run this code twice if
134        * init_connections_unlocked() fails midway through.
135        */
136       
137        if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
138          {
139            if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM],
140                               "DBUS_SYSTEM_BUS_ADDRESS"))
141              return FALSE;
142            
143            if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
144              {
145                /* Use default system bus address if none set in environment */
146                bus_connection_addresses[DBUS_BUS_SYSTEM] =
147                  _dbus_strdup ("unix:path=" DBUS_SYSTEM_BUS_PATH);
148                if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
149                  return FALSE;
150              }
151          }
152           
153       if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
154         {
155           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
156                              "DBUS_SESSION_BUS_ADDRESS"))
157             return FALSE;
158         }
159
160       if (bus_connection_addresses[DBUS_BUS_ACTIVATION] == NULL)
161         {
162           if (!get_from_env (&bus_connection_addresses[DBUS_BUS_ACTIVATION],
163                              "DBUS_ACTIVATION_ADDRESS"))
164             return FALSE;
165         }
166
167       s = _dbus_getenv ("DBUS_ACTIVATION_BUS_TYPE");
168
169       if (s != NULL)
170         {
171           if (strcmp (s, "system") == 0)
172             activation_bus_type = DBUS_BUS_SYSTEM;
173           else if (strcmp (s, "session") == 0)
174             activation_bus_type = DBUS_BUS_SESSION;
175         }
176
177       /* If we return FALSE we have to be sure that restarting
178        * the above code will work right
179        */
180       
181       if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL))
182         return FALSE;
183
184       if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL))
185         return FALSE;
186       
187       if (!_dbus_register_shutdown_func (addresses_shutdown_func,
188                                          NULL))
189         return FALSE;
190       
191       initialized = TRUE;
192     }
193
194   return initialized;
195 }
196
197 static dbus_bool_t
198 data_slot_ref (void)
199 {
200   _DBUS_LOCK (bus);
201
202   if (bus_data_slot < 0)
203     {
204       bus_data_slot = dbus_connection_allocate_data_slot ();
205       
206       if (bus_data_slot < 0)
207         {
208           _DBUS_UNLOCK (bus);
209           return FALSE;
210         }
211
212       _dbus_assert (bus_data_slot_refcount == 0);
213     }
214
215   bus_data_slot_refcount += 1;
216
217   _DBUS_UNLOCK (bus);
218
219   return TRUE;
220 }
221
222 static void
223 data_slot_unref (void)
224 {
225   _DBUS_LOCK (bus);
226
227   _dbus_assert (bus_data_slot_refcount > 0);
228   _dbus_assert (bus_data_slot >= 0);
229
230   bus_data_slot_refcount -= 1;
231
232   if (bus_data_slot_refcount == 0)
233     {
234       dbus_connection_free_data_slot (bus_data_slot);
235       bus_data_slot = -1;
236     }
237
238   _DBUS_UNLOCK (bus);
239 }
240
241 static void
242 bus_data_free (void *data)
243 {
244   BusData *bd = data;
245   
246   if (bd->is_well_known)
247     {
248       int i;
249       _DBUS_LOCK (bus);
250       /* We may be stored in more than one slot */
251       i = 0;
252       while (i < N_BUS_TYPES)
253         {
254           if (bus_connections[i] == bd->connection)
255             bus_connections[i] = NULL;
256           
257           ++i;
258         }
259       _DBUS_UNLOCK (bus);
260     }
261   
262   dbus_free (bd->base_service);
263   dbus_free (bd);
264
265   data_slot_unref ();
266 }
267
268 static BusData*
269 ensure_bus_data (DBusConnection *connection)
270 {
271   BusData *bd;
272
273   if (!data_slot_ref ())
274     return NULL;
275
276   bd = dbus_connection_get_data (connection, bus_data_slot);
277   if (bd == NULL)
278     {      
279       bd = dbus_new0 (BusData, 1);
280       if (bd == NULL)
281         {
282           data_slot_unref ();
283           return NULL;
284         }
285
286       bd->connection = connection;
287       
288       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
289                                      bus_data_free))
290         {
291           dbus_free (bd);
292           data_slot_unref ();
293           return NULL;
294         }
295
296       /* Data slot refcount now held by the BusData */
297     }
298   else
299     {
300       data_slot_unref ();
301     }
302
303   return bd;
304 }
305
306 /** @} */ /* end of implementation details docs */
307
308 /**
309  * @addtogroup DBusBus
310  * @{
311  */
312
313 /**
314  * Connects to a bus daemon and registers the client with it.
315  * If a connection to the bus already exists, then that connection is returned.
316  *
317  * @todo alex thinks we should nullify the connection when we get a disconnect-message.
318  *
319  * @param type bus type
320  * @param error address where an error can be returned.
321  * @returns a DBusConnection
322  */
323 DBusConnection *
324 dbus_bus_get (DBusBusType  type,
325               DBusError   *error)
326 {
327   const char *address;
328   DBusConnection *connection;
329   BusData *bd;
330   DBusBusType address_type;
331
332   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
333   
334   if (type < 0 || type >= N_BUS_TYPES)
335     {
336       _dbus_assert_not_reached ("Invalid bus type specified.");
337
338       return NULL;
339     }
340
341   _DBUS_LOCK (bus);
342
343   if (!init_connections_unlocked ())
344     {
345       _DBUS_UNLOCK (bus);
346       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
347       return NULL;
348     }
349
350   /* We want to use the activation address even if the
351    * activating bus is the session or system bus,
352    * per the spec.
353    */
354   address_type = type;
355   
356   /* Use the real type of the activation bus for getting its
357    * connection. (If the activating bus isn't a well-known
358    * bus then activation_bus_type == DBUS_BUS_ACTIVATION)
359    */
360   if (type == DBUS_BUS_ACTIVATION)
361     type = activation_bus_type;
362   
363   if (bus_connections[type] != NULL)
364     {
365       connection = bus_connections[type];
366       dbus_connection_ref (connection);
367       
368       _DBUS_UNLOCK (bus);
369       return connection;
370     }
371
372   address = bus_connection_addresses[address_type];
373   if (address == NULL)
374     {
375       dbus_set_error (error, DBUS_ERROR_FAILED,
376                       "Unable to determine the address of the message bus");
377       _DBUS_UNLOCK (bus);
378       return NULL;
379     }
380
381   connection = dbus_connection_open (address, error);
382   
383   if (!connection)
384     {
385       _DBUS_ASSERT_ERROR_IS_SET (error);
386       _DBUS_UNLOCK (bus);
387       return NULL;
388     }
389   
390   if (!dbus_bus_register (connection, error))
391     {
392       _DBUS_ASSERT_ERROR_IS_SET (error);
393       dbus_connection_disconnect (connection);
394       dbus_connection_unref (connection);
395
396       _DBUS_UNLOCK (bus);
397       return NULL;
398     }
399
400   bus_connections[type] = connection;
401   bd = ensure_bus_data (connection);
402   _dbus_assert (bd != NULL);
403
404   bd->is_well_known = TRUE;
405
406   _DBUS_UNLOCK (bus);
407   return connection;
408 }
409
410
411 /**
412  * Registers a connection with the bus. This must be the first
413  * thing an application does when connecting to the message bus.
414  * If registration succeeds, the base service name will be set,
415  * and can be obtained using dbus_bus_get_base_service().
416  *
417  * @todo if we get an error reply, it has to be converted into
418  * DBusError and returned
419  * 
420  * @param connection the connection
421  * @param error place to store errors
422  * @returns #TRUE on success
423  */
424 dbus_bool_t
425 dbus_bus_register (DBusConnection *connection,
426                    DBusError      *error)
427 {
428   DBusMessage *message, *reply;
429   char *name;
430   BusData *bd;
431   dbus_bool_t retval;
432   
433   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
434
435   retval = FALSE;
436   
437   bd = ensure_bus_data (connection);
438   if (bd == NULL)
439     {
440       _DBUS_SET_OOM (error);
441       return FALSE;
442     }
443
444   if (bd->base_service != NULL)
445     {
446       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
447       /* This isn't an error, it's a programming bug. We'll be nice
448        * and not _dbus_assert_not_reached()
449        */
450       return TRUE;
451     }
452   
453   message = dbus_message_new (DBUS_SERVICE_DBUS,
454                               DBUS_MESSAGE_HELLO);
455
456   if (!message)
457     {
458       _DBUS_SET_OOM (error);
459       return FALSE;
460     }
461   
462   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
463
464   dbus_message_unref (message);
465   
466   if (reply == NULL)
467     goto out;
468   else if (dbus_set_error_from_message (error, reply))
469     goto out;
470   else if (!dbus_message_get_args (reply, error,
471                                    DBUS_TYPE_STRING, &name,
472                                    0))
473     goto out;
474   
475   bd->base_service = name;
476
477   retval = TRUE;
478   
479  out:
480   if (reply)
481     dbus_message_unref (reply);
482
483   if (!retval)
484     _DBUS_ASSERT_ERROR_IS_SET (error);
485   
486   return retval;
487 }
488
489
490 /**
491  * Sets the base service name of the connection.
492  * Can only be used if you registered with the
493  * bus manually (i.e. if you did not call
494  * dbus_bus_register()). Can only be called
495  * once per connection.
496  *
497  * @param connection the connection
498  * @param base_service the base service name
499  * @returns #FALSE if not enough memory
500  */
501 dbus_bool_t
502 dbus_bus_set_base_service (DBusConnection *connection,
503                            const char     *base_service)
504 {
505   BusData *bd;
506
507   bd = ensure_bus_data (connection);
508   if (bd == NULL)
509     return FALSE;
510
511   _dbus_assert (bd->base_service == NULL);
512   _dbus_assert (base_service != NULL);
513   
514   bd->base_service = _dbus_strdup (base_service);
515   return bd->base_service != NULL;
516 }
517
518 /**
519  * Gets the base service name of the connection.
520  * Only possible after the connection has been registered
521  * with the message bus.
522  *
523  * @param connection the connection
524  * @returns the base service name
525  */
526 const char*
527 dbus_bus_get_base_service (DBusConnection *connection)
528 {
529   BusData *bd;
530
531   bd = ensure_bus_data (connection);
532   if (bd == NULL)
533     return NULL;
534   
535   return bd->base_service;
536 }
537
538 /**
539  * Asks the bus to try to acquire a certain service.
540  *
541  * @todo these docs are not complete, need to document the
542  * return value and flags
543  * 
544  * @todo if we get an error reply, it has to be converted into
545  * DBusError and returned
546  *
547  * @param connection the connection
548  * @param service_name the service name
549  * @param flags flags
550  * @param error location to store the error
551  * @returns a result code, -1 if error is set
552  */ 
553 int
554 dbus_bus_acquire_service (DBusConnection *connection,
555                           const char     *service_name,
556                           unsigned int    flags,
557                           DBusError      *error)
558 {
559   DBusMessage *message, *reply;
560   dbus_uint32_t service_result;
561   
562   message = dbus_message_new (DBUS_SERVICE_DBUS,
563                               DBUS_MESSAGE_ACQUIRE_SERVICE);
564
565   if (message == NULL)
566     {
567       _DBUS_SET_OOM (error);
568       return -1;
569     }
570  
571   if (!dbus_message_append_args (message,
572                                  DBUS_TYPE_STRING, service_name,
573                                  DBUS_TYPE_UINT32, flags,
574                                  0))
575     {
576       dbus_message_unref (message);
577       _DBUS_SET_OOM (error);
578       return -1;
579     }
580   
581   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
582                                                      error);
583   
584   dbus_message_unref (message);
585   
586   if (reply == NULL)
587     {
588       _DBUS_ASSERT_ERROR_IS_SET (error);
589       return -1;
590     }  
591
592   if (dbus_set_error_from_message (error, reply))
593     {
594       _DBUS_ASSERT_ERROR_IS_SET (error);
595       dbus_message_unref (reply);
596       return -1;
597     }
598   
599   if (!dbus_message_get_args (reply, error,
600                               DBUS_TYPE_UINT32, &service_result,
601                               0))
602     {
603       _DBUS_ASSERT_ERROR_IS_SET (error);
604       dbus_message_unref (reply);
605       return -1;
606     }
607
608   dbus_message_unref (reply);
609   
610   return service_result;
611 }
612
613 /**
614  * Checks whether a certain service exists.
615  *
616  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
617  *
618  * @param connection the connection
619  * @param service_name the service name
620  * @param error location to store any errors
621  * @returns #TRUE if the service exists, #FALSE if not or on error
622  */
623 dbus_bool_t
624 dbus_bus_service_exists (DBusConnection *connection,
625                          const char     *service_name,
626                          DBusError      *error)
627 {
628   DBusMessage *message, *reply;
629   unsigned int exists;
630
631   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
632   
633   message = dbus_message_new (DBUS_SERVICE_DBUS,
634                               DBUS_MESSAGE_SERVICE_EXISTS);
635   if (message == NULL)
636     {
637       _DBUS_SET_OOM (error);
638       return FALSE;
639     }
640   
641   if (!dbus_message_append_args (message,
642                                  DBUS_TYPE_STRING, service_name,
643                                  0))
644     {
645       dbus_message_unref (message);
646       _DBUS_SET_OOM (error);
647       return FALSE;
648     }
649   
650   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
651   dbus_message_unref (message);
652
653   if (reply == NULL)
654     {
655       _DBUS_ASSERT_ERROR_IS_SET (error);
656       return FALSE;
657     }
658
659   if (!dbus_message_get_args (reply, error,
660                               DBUS_TYPE_UINT32, &exists,
661                               0))
662     {
663       _DBUS_ASSERT_ERROR_IS_SET (error);
664       return FALSE;
665     }
666   
667   return (exists != FALSE);
668 }
669
670 /** @} */