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