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