2003-08-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 "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_INTERFACE_ORG_FREEDESKTOP_DBUS,
407                                           "Hello",
408                                           DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
409                               
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_INTERFACE_ORG_FREEDESKTOP_DBUS,
526                                           "AcquireService",
527                                           DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
528
529   if (message == NULL)
530     {
531       _DBUS_SET_OOM (error);
532       return -1;
533     }
534  
535   if (!dbus_message_append_args (message,
536                                  DBUS_TYPE_STRING, service_name,
537                                  DBUS_TYPE_UINT32, flags,
538                                  DBUS_TYPE_INVALID))
539     {
540       dbus_message_unref (message);
541       _DBUS_SET_OOM (error);
542       return -1;
543     }
544   
545   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
546                                                      error);
547   
548   dbus_message_unref (message);
549   
550   if (reply == NULL)
551     {
552       _DBUS_ASSERT_ERROR_IS_SET (error);
553       return -1;
554     }  
555
556   if (dbus_set_error_from_message (error, reply))
557     {
558       _DBUS_ASSERT_ERROR_IS_SET (error);
559       dbus_message_unref (reply);
560       return -1;
561     }
562   
563   if (!dbus_message_get_args (reply, error,
564                               DBUS_TYPE_UINT32, &service_result,
565                               DBUS_TYPE_INVALID))
566     {
567       _DBUS_ASSERT_ERROR_IS_SET (error);
568       dbus_message_unref (reply);
569       return -1;
570     }
571
572   dbus_message_unref (reply);
573   
574   return service_result;
575 }
576
577 /**
578  * Checks whether a certain service exists.
579  *
580  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
581  *
582  * @param connection the connection
583  * @param service_name the service name
584  * @param error location to store any errors
585  * @returns #TRUE if the service exists, #FALSE if not or on error
586  */
587 dbus_bool_t
588 dbus_bus_service_exists (DBusConnection *connection,
589                          const char     *service_name,
590                          DBusError      *error)
591 {
592   DBusMessage *message, *reply;
593   unsigned int exists;
594
595   _dbus_return_val_if_fail (connection != NULL, FALSE);
596   _dbus_return_val_if_fail (service_name != NULL, FALSE);
597   _dbus_return_val_if_error_is_set (error, FALSE);
598   
599   message = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
600                                           "ServiceExists",
601                                           DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
602   if (message == NULL)
603     {
604       _DBUS_SET_OOM (error);
605       return FALSE;
606     }
607   
608   if (!dbus_message_append_args (message,
609                                  DBUS_TYPE_STRING, service_name,
610                                  DBUS_TYPE_INVALID))
611     {
612       dbus_message_unref (message);
613       _DBUS_SET_OOM (error);
614       return FALSE;
615     }
616   
617   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
618   dbus_message_unref (message);
619
620   if (reply == NULL)
621     {
622       _DBUS_ASSERT_ERROR_IS_SET (error);
623       return FALSE;
624     }
625
626   if (!dbus_message_get_args (reply, error,
627                               DBUS_TYPE_UINT32, &exists,
628                               DBUS_TYPE_INVALID))
629     {
630       _DBUS_ASSERT_ERROR_IS_SET (error);
631       return FALSE;
632     }
633   
634   return (exists != FALSE);
635 }
636
637 /**
638  * Activates a given service
639  *
640  * @param connection the connection
641  * @param service_name the service name
642  * @param flags the flags
643  * @param result a place to store the result of the activation, which will
644  * be one of DBUS_ACTIVATION_REPLY_ACTIVATED or
645  * DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE if successful.  Pass NULL if you
646  * don't care about the result.
647  * @param error location to store any errors
648  * @returns #TRUE if the activation succeeded, #FALSE if not
649  *
650  * @todo document what the flags do
651  */
652 dbus_bool_t
653 dbus_bus_activate_service (DBusConnection *connection,
654                            const char     *service_name,
655                            dbus_uint32_t   flags,
656                            dbus_uint32_t  *result,
657                            DBusError      *error)
658 {
659   DBusMessage *msg;
660   DBusMessage *reply;
661
662   msg = dbus_message_new_method_call (DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
663                                       "ActivateService",
664                                       DBUS_SERVICE_ORG_FREEDESKTOP_DBUS);
665
666   if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
667                                  DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
668     {
669       dbus_message_unref (msg);
670       _DBUS_SET_OOM (error);
671       return FALSE;
672     }
673
674   reply = dbus_connection_send_with_reply_and_block (connection, msg,
675                                                          -1, error);
676   dbus_message_unref (msg);
677
678   if (reply == NULL)
679     {
680       _DBUS_ASSERT_ERROR_IS_SET (error);
681       return FALSE;
682     }
683
684   if (dbus_set_error_from_message (error, reply))
685     {
686       _DBUS_ASSERT_ERROR_IS_SET (error);
687       dbus_message_unref (reply);
688       return FALSE;
689     }
690
691   if (result != NULL &&
692       !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
693                               result, DBUS_TYPE_INVALID))
694     {
695       _DBUS_ASSERT_ERROR_IS_SET (error);
696       dbus_message_unref (reply);
697       return FALSE;
698     }
699   
700   dbus_message_unref (reply);
701   return TRUE;
702 }
703
704
705 /** @} */