2003-08-30 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 "dbus-message.h"
29 #include <string.h>
30
31 /**
32  * @defgroup DBusBus Message bus APIs
33  * @ingroup DBus
34  * @brief Functions for communicating with the message bus
35  *
36  *
37  * @todo get rid of most of these; they should be done
38  * with DBusGProxy and the Qt equivalent, i.e. the same
39  * way any other interface would be used.
40  */
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 ("unix:path=" DBUS_SYSTEM_BUS_PATH);
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_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
407                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
408                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
409                                           "Hello"); 
410
411   if (!message)
412     {
413       _DBUS_SET_OOM (error);
414       return FALSE;
415     }
416   
417   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
418
419   dbus_message_unref (message);
420   
421   if (reply == NULL)
422     goto out;
423   else if (dbus_set_error_from_message (error, reply))
424     goto out;
425   else if (!dbus_message_get_args (reply, error,
426                                    DBUS_TYPE_STRING, &name,
427                                    DBUS_TYPE_INVALID))
428     goto out;
429   
430   bd->base_service = name;
431
432   retval = TRUE;
433   
434  out:
435   if (reply)
436     dbus_message_unref (reply);
437
438   if (!retval)
439     _DBUS_ASSERT_ERROR_IS_SET (error);
440   
441   return retval;
442 }
443
444
445 /**
446  * Sets the base service name of the connection.
447  * Can only be used if you registered with the
448  * bus manually (i.e. if you did not call
449  * dbus_bus_register()). Can only be called
450  * once per connection.
451  *
452  * @param connection the connection
453  * @param base_service the base service name
454  * @returns #FALSE if not enough memory
455  */
456 dbus_bool_t
457 dbus_bus_set_base_service (DBusConnection *connection,
458                            const char     *base_service)
459 {
460   BusData *bd;
461
462   _dbus_return_val_if_fail (connection != NULL, FALSE);
463   _dbus_return_val_if_fail (base_service != NULL, FALSE);
464   
465   bd = ensure_bus_data (connection);
466   if (bd == NULL)
467     return FALSE;
468
469   _dbus_assert (bd->base_service == NULL);
470   
471   bd->base_service = _dbus_strdup (base_service);
472   return bd->base_service != NULL;
473 }
474
475 /**
476  * Gets the base service name of the connection.
477  * Only possible after the connection has been registered
478  * with the message bus.
479  *
480  * @param connection the connection
481  * @returns the base service name
482  */
483 const char*
484 dbus_bus_get_base_service (DBusConnection *connection)
485 {
486   BusData *bd;
487
488   _dbus_return_val_if_fail (connection != NULL, NULL);
489   
490   bd = ensure_bus_data (connection);
491   if (bd == NULL)
492     return NULL;
493   
494   return bd->base_service;
495 }
496
497 /**
498  * Asks the bus to try to acquire a certain service.
499  *
500  * @todo these docs are not complete, need to document the
501  * return value and flags
502  * 
503  * @todo if we get an error reply, it has to be converted into
504  * DBusError and returned
505  *
506  * @param connection the connection
507  * @param service_name the service name
508  * @param flags flags
509  * @param error location to store the error
510  * @returns a result code, -1 if error is set
511  */ 
512 int
513 dbus_bus_acquire_service (DBusConnection *connection,
514                           const char     *service_name,
515                           unsigned int    flags,
516                           DBusError      *error)
517 {
518   DBusMessage *message, *reply;
519   dbus_uint32_t service_result;
520
521   _dbus_return_val_if_fail (connection != NULL, 0);
522   _dbus_return_val_if_fail (service_name != NULL, 0);
523   _dbus_return_val_if_error_is_set (error, 0);
524   
525   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
526                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
527                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
528                                           "AcquireService");
529
530   if (message == NULL)
531     {
532       _DBUS_SET_OOM (error);
533       return -1;
534     }
535  
536   if (!dbus_message_append_args (message,
537                                  DBUS_TYPE_STRING, service_name,
538                                  DBUS_TYPE_UINT32, flags,
539                                  DBUS_TYPE_INVALID))
540     {
541       dbus_message_unref (message);
542       _DBUS_SET_OOM (error);
543       return -1;
544     }
545   
546   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
547                                                      error);
548   
549   dbus_message_unref (message);
550   
551   if (reply == NULL)
552     {
553       _DBUS_ASSERT_ERROR_IS_SET (error);
554       return -1;
555     }  
556
557   if (dbus_set_error_from_message (error, reply))
558     {
559       _DBUS_ASSERT_ERROR_IS_SET (error);
560       dbus_message_unref (reply);
561       return -1;
562     }
563   
564   if (!dbus_message_get_args (reply, error,
565                               DBUS_TYPE_UINT32, &service_result,
566                               DBUS_TYPE_INVALID))
567     {
568       _DBUS_ASSERT_ERROR_IS_SET (error);
569       dbus_message_unref (reply);
570       return -1;
571     }
572
573   dbus_message_unref (reply);
574   
575   return service_result;
576 }
577
578 /**
579  * Checks whether a certain service exists.
580  *
581  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
582  *
583  * @param connection the connection
584  * @param service_name the service name
585  * @param error location to store any errors
586  * @returns #TRUE if the service exists, #FALSE if not or on error
587  */
588 dbus_bool_t
589 dbus_bus_service_exists (DBusConnection *connection,
590                          const char     *service_name,
591                          DBusError      *error)
592 {
593   DBusMessage *message, *reply;
594   unsigned int exists;
595
596   _dbus_return_val_if_fail (connection != NULL, FALSE);
597   _dbus_return_val_if_fail (service_name != NULL, FALSE);
598   _dbus_return_val_if_error_is_set (error, FALSE);
599   
600   message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
601                                           DBUS_PATH_ORG_FREEDESKTOP_DBUS,
602                                           DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
603                                           "ServiceExists");
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_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
665                                       DBUS_PATH_ORG_FREEDESKTOP_DBUS,
666                                       DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
667                                       "ActivateService");
668
669   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
670                                  DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
671     {
672       dbus_message_unref (msg);
673       _DBUS_SET_OOM (error);
674       return FALSE;
675     }
676
677   reply = dbus_connection_send_with_reply_and_block (connection, msg,
678                                                          -1, error);
679   dbus_message_unref (msg);
680
681   if (reply == NULL)
682     {
683       _DBUS_ASSERT_ERROR_IS_SET (error);
684       return FALSE;
685     }
686
687   if (dbus_set_error_from_message (error, reply))
688     {
689       _DBUS_ASSERT_ERROR_IS_SET (error);
690       dbus_message_unref (reply);
691       return FALSE;
692     }
693
694   if (result != NULL &&
695       !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
696                               result, DBUS_TYPE_INVALID))
697     {
698       _DBUS_ASSERT_ERROR_IS_SET (error);
699       dbus_message_unref (reply);
700       return FALSE;
701     }
702   
703   dbus_message_unref (reply);
704   return TRUE;
705 }
706
707
708 /** @} */