2003-04-06 Havoc Pennington <hp@pobox.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
432   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
433   
434   bd = ensure_bus_data (connection);
435   if (bd == NULL)
436     {
437       _DBUS_SET_OOM (error);
438       return FALSE;
439     }
440
441   if (bd->base_service != NULL)
442     {
443       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
444       /* This isn't an error, it's a programming bug. We'll be nice
445        * and not _dbus_assert_not_reached()
446        */
447       return TRUE;
448     }
449   
450   message = dbus_message_new (DBUS_SERVICE_DBUS,
451                               DBUS_MESSAGE_HELLO);
452
453   if (!message)
454     {
455       _DBUS_SET_OOM (error);
456       return FALSE;
457     }
458   
459   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
460
461   dbus_message_unref (message);
462   
463   if (reply == NULL)
464     {
465       _DBUS_ASSERT_ERROR_IS_SET (error);
466       return FALSE;
467     }
468
469   if (!dbus_message_get_args (reply, error,
470                               DBUS_TYPE_STRING, &name,
471                               0))
472     {
473       _DBUS_ASSERT_ERROR_IS_SET (error);
474       return FALSE;
475     }
476
477   bd->base_service = name;
478   
479   return TRUE;
480 }
481
482
483 /**
484  * Sets the base service name of the connection.
485  * Can only be used if you registered with the
486  * bus manually (i.e. if you did not call
487  * dbus_bus_register()). Can only be called
488  * once per connection.
489  *
490  * @param connection the connection
491  * @param base_service the base service name
492  * @returns #FALSE if not enough memory
493  */
494 dbus_bool_t
495 dbus_bus_set_base_service (DBusConnection *connection,
496                            const char     *base_service)
497 {
498   BusData *bd;
499
500   bd = ensure_bus_data (connection);
501   if (bd == NULL)
502     return FALSE;
503
504   _dbus_assert (bd->base_service == NULL);
505   _dbus_assert (base_service != NULL);
506   
507   bd->base_service = _dbus_strdup (base_service);
508   return bd->base_service != NULL;
509 }
510
511 /**
512  * Gets the base service name of the connection.
513  * Only possible after the connection has been registered
514  * with the message bus.
515  *
516  * @param connection the connection
517  * @returns the base service name
518  */
519 const char*
520 dbus_bus_get_base_service (DBusConnection *connection)
521 {
522   BusData *bd;
523
524   bd = ensure_bus_data (connection);
525   if (bd == NULL)
526     return NULL;
527   
528   return bd->base_service;
529 }
530
531 /**
532  * Asks the bus to try to acquire a certain service.
533  *
534  * @todo these docs are not complete, need to document the
535  * return value and flags
536  * 
537  * @todo if we get an error reply, it has to be converted into
538  * DBusError and returned
539  *
540  * @param connection the connection
541  * @param service_name the service name
542  * @param flags flags
543  * @param error location to store the error
544  * @returns a result code, -1 if error is set
545  */ 
546 int
547 dbus_bus_acquire_service (DBusConnection *connection,
548                           const char     *service_name,
549                           unsigned int    flags,
550                           DBusError      *error)
551 {
552   DBusMessage *message, *reply;
553   dbus_uint32_t service_result;
554   
555   message = dbus_message_new (DBUS_SERVICE_DBUS,
556                               DBUS_MESSAGE_ACQUIRE_SERVICE);
557
558   if (message == NULL)
559     {
560       _DBUS_SET_OOM (error);
561       return -1;
562     }
563  
564   if (!dbus_message_append_args (message,
565                                  DBUS_TYPE_STRING, service_name,
566                                  DBUS_TYPE_UINT32, flags,
567                                  0))
568     {
569       dbus_message_unref (message);
570       _DBUS_SET_OOM (error);
571       return -1;
572     }
573   
574   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
575                                                      error);
576   
577   dbus_message_unref (message);
578   
579   if (reply == NULL)
580     {
581       _DBUS_ASSERT_ERROR_IS_SET (error);
582       return -1;
583     }  
584
585   if (dbus_set_error_from_message (error, reply))
586     {
587       _DBUS_ASSERT_ERROR_IS_SET (error);
588       dbus_message_unref (reply);
589       return -1;
590     }
591   
592   if (!dbus_message_get_args (reply, error,
593                               DBUS_TYPE_UINT32, &service_result,
594                               0))
595     {
596       _DBUS_ASSERT_ERROR_IS_SET (error);
597       dbus_message_unref (reply);
598       return -1;
599     }
600
601   dbus_message_unref (reply);
602   
603   return service_result;
604 }
605
606 /**
607  * Checks whether a certain service exists.
608  *
609  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
610  *
611  * @param connection the connection
612  * @param service_name the service name
613  * @param error location to store any errors
614  * @returns #TRUE if the service exists, #FALSE if not or on error
615  */
616 dbus_bool_t
617 dbus_bus_service_exists (DBusConnection *connection,
618                          const char     *service_name,
619                          DBusError      *error)
620 {
621   DBusMessage *message, *reply;
622   unsigned int exists;
623
624   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
625   
626   message = dbus_message_new (DBUS_SERVICE_DBUS,
627                               DBUS_MESSAGE_SERVICE_EXISTS);
628   if (message == NULL)
629     {
630       _DBUS_SET_OOM (error);
631       return FALSE;
632     }
633   
634   if (!dbus_message_append_args (message,
635                                  DBUS_TYPE_STRING, service_name,
636                                  0))
637     {
638       dbus_message_unref (message);
639       _DBUS_SET_OOM (error);
640       return FALSE;
641     }
642   
643   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
644   dbus_message_unref (message);
645
646   if (reply == NULL)
647     {
648       _DBUS_ASSERT_ERROR_IS_SET (error);
649       return FALSE;
650     }
651
652   if (!dbus_message_get_args (reply, error,
653                               DBUS_TYPE_UINT32, &exists,
654                               0))
655     {
656       _DBUS_ASSERT_ERROR_IS_SET (error);
657       return FALSE;
658     }
659   
660   return (exists != FALSE);
661 }
662
663 /** @} */