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