2003-03-28 Anders Carlsson <andersca@codefactory.se>
[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
29 /**
30  * @defgroup DBusBus Message bus APIs
31  * @ingroup DBus
32  * @brief Functions for communicating with the message bus
33  *
34  */
35
36
37 /**
38  * @defgroup DBusBusInternals Message bus APIs internals
39  * @ingroup DBusInternals
40  * @brief Internals of functions for communicating with the message bus
41  *
42  * @{
43  */
44
45 /**
46  * Block of message-bus-related data we attach to each
47  * #DBusConnection used with these convenience functions.
48  *
49  */
50 typedef struct
51 {
52   char *base_service; /**< Base service name of this connection */
53
54   DBusConnection **connection; /**< Pointer to bus_connections entry */
55 } BusData;
56
57 /** The slot we have reserved to store BusData
58  */
59 static int bus_data_slot = -1;
60 /** Number of connections using the slot
61  */
62 static int bus_data_slot_refcount = 0;
63
64 /**
65  * Lock for bus_data_slot and bus_data_slot_refcount
66  */
67 _DBUS_DEFINE_GLOBAL_LOCK (bus);
68
69
70 static dbus_bool_t
71 data_slot_ref (void)
72 {
73   _DBUS_LOCK (bus);
74
75   if (bus_data_slot < 0)
76     {
77       bus_data_slot = dbus_connection_allocate_data_slot ();
78       
79       if (bus_data_slot < 0)
80         {
81           _DBUS_UNLOCK (bus);
82           return FALSE;
83         }
84
85       _dbus_assert (bus_data_slot_refcount == 0);
86     }
87
88   bus_data_slot_refcount += 1;
89
90   _DBUS_UNLOCK (bus);
91
92   return TRUE;
93 }
94
95 static void
96 data_slot_unref (void)
97 {
98   _DBUS_LOCK (bus);
99
100   _dbus_assert (bus_data_slot_refcount > 0);
101   _dbus_assert (bus_data_slot >= 0);
102
103   bus_data_slot_refcount -= 1;
104
105   if (bus_data_slot_refcount == 0)
106     {
107       dbus_connection_free_data_slot (bus_data_slot);
108       bus_data_slot = -1;
109     }
110
111   _DBUS_UNLOCK (bus);
112 }
113
114 static void
115 bus_data_free (void *data)
116 {
117   BusData *bd = data;
118
119   if (bd->connection)
120     *bd->connection = NULL;
121   
122   dbus_free (bd->base_service);
123   dbus_free (bd);
124
125   data_slot_unref ();
126 }
127
128 static BusData*
129 ensure_bus_data (DBusConnection *connection)
130 {
131   BusData *bd;
132
133   if (!data_slot_ref ())
134     return NULL;
135
136   bd = dbus_connection_get_data (connection, bus_data_slot);
137   if (bd == NULL)
138     {      
139       bd = dbus_new0 (BusData, 1);
140       if (bd == NULL)
141         {
142           data_slot_unref ();
143           return NULL;
144         }
145       
146       if (!dbus_connection_set_data (connection, bus_data_slot, bd,
147                                      bus_data_free))
148         {
149           dbus_free (bd);
150           data_slot_unref ();
151           return NULL;
152         }
153
154       /* Data slot refcount now held by the BusData */
155     }
156   else
157     {
158       data_slot_unref ();
159     }
160
161   return bd;
162 }
163
164 /** @} */ /* end of implementation details docs */
165
166 /**
167  * @addtogroup DBusBus
168  * @{
169  */
170
171 /** Number of bus types */
172 #define BUS_TYPES 2
173
174 static DBusConnection *bus_connections[BUS_TYPES];
175
176 /**
177  * Connects to a bus daemon and registers the client with it.
178  * If a connection to the bus already exists, then that connection is returned.
179  *
180  * @todo alex thinks we should nullify the connection when we get a disconnect-message.
181  *
182  * @param type bus type
183  * @param error address where an error can be returned.
184  * @returns a DBusConnection
185  */
186 DBusConnection *
187 dbus_bus_get (DBusBusType  type,
188               DBusError   *error)
189 {
190   const char *name, *value;
191   DBusConnection *connection;
192   BusData *bd;
193
194   if (type <= 0 || type >= BUS_TYPES)
195     {
196       _dbus_assert_not_reached ("Invalid bus type specified.");
197
198       return NULL;
199     }
200
201   _DBUS_LOCK (bus);
202   
203   if (bus_connections[type] != NULL)
204     {
205       connection = bus_connections[type];
206       dbus_connection_ref (connection);
207       
208       _DBUS_UNLOCK (bus);
209       return connection;
210     }
211
212   switch (type)
213     {
214     case DBUS_BUS_SESSION:
215       name = "DBUS_SESSION_BUS_ADDRESS";
216       break;
217     case DBUS_BUS_SYSTEM:
218       name = "DBUS_SYSTEM_BUS_ADDRESS";
219       break;
220     }
221
222   value = _dbus_getenv (name);
223
224   if (!value)
225     {
226       dbus_set_error (error, DBUS_ERROR_FAILED,
227                       "Could not get bus daemon address.");
228       _DBUS_UNLOCK (bus);
229       
230       return NULL;
231     }
232
233   connection = dbus_connection_open (value, error);
234   
235   if (!connection)
236     {
237       _DBUS_UNLOCK (bus);
238       return NULL;
239     }
240   
241   if (!dbus_bus_register (connection, error))
242     {
243       dbus_connection_disconnect (connection);
244       dbus_connection_unref (connection);
245
246       _DBUS_UNLOCK (bus);
247       return NULL;
248     }
249
250   bus_connections[type] = connection;
251   bd = ensure_bus_data (connection);
252   _dbus_assert (bd != NULL);
253
254   bd->connection = &bus_connections[type];
255
256   _DBUS_UNLOCK (bus);  
257   return connection;
258 }
259
260
261 /**
262  * Registers a connection with the bus. This must be the first
263  * thing an application does when connecting to the message bus.
264  * If registration succeeds, the base service name will be set,
265  * and can be obtained using dbus_bus_get_base_service().
266  *
267  * @todo if we get an error reply, it has to be converted into
268  * DBusError and returned
269  * 
270  * @param connection the connection
271  * @param error place to store errors
272  * @returns #TRUE on success
273  */
274 dbus_bool_t
275 dbus_bus_register (DBusConnection *connection,
276                    DBusError      *error)
277 {
278   DBusMessage *message, *reply;
279   char *name;
280   BusData *bd;
281
282   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
283   
284   bd = ensure_bus_data (connection);
285   if (bd == NULL)
286     {
287       _DBUS_SET_OOM (error);
288       return FALSE;
289     }
290
291   if (bd->base_service != NULL)
292     {
293       _dbus_warn ("Attempt to register the same DBusConnection with the message bus, but it is already registered\n");
294       /* This isn't an error, it's a programming bug. We'll be nice
295        * and not _dbus_assert_not_reached()
296        */
297       return TRUE;
298     }
299   
300   message = dbus_message_new (DBUS_SERVICE_DBUS,
301                               DBUS_MESSAGE_HELLO);
302
303   if (!message)
304     {
305       _DBUS_SET_OOM (error);
306       return FALSE;
307     }
308   
309   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
310
311   dbus_message_unref (message);
312   
313   if (reply == NULL)
314     {
315       _DBUS_ASSERT_ERROR_IS_SET (error);
316       return FALSE;
317     }
318
319   if (!dbus_message_get_args (reply, error,
320                               DBUS_TYPE_STRING, &name,
321                               0))
322     {
323       _DBUS_ASSERT_ERROR_IS_SET (error);
324       return FALSE;
325     }
326
327   bd->base_service = name;
328   
329   return TRUE;
330 }
331
332
333 /**
334  * Sets the base service name of the connection.
335  * Can only be used if you registered with the
336  * bus manually (i.e. if you did not call
337  * dbus_bus_register()). Can only be called
338  * once per connection.
339  *
340  * @param connection the connection
341  * @param base_service the base service name
342  * @returns #FALSE if not enough memory
343  */
344 dbus_bool_t
345 dbus_bus_set_base_service (DBusConnection *connection,
346                            const char     *base_service)
347 {
348   BusData *bd;
349
350   bd = ensure_bus_data (connection);
351   if (bd == NULL)
352     return FALSE;
353
354   _dbus_assert (bd->base_service == NULL);
355   _dbus_assert (base_service != NULL);
356   
357   bd->base_service = _dbus_strdup (base_service);
358   return bd->base_service != NULL;
359 }
360
361 /**
362  * Gets the base service name of the connection.
363  * Only possible after the connection has been registered
364  * with the message bus.
365  *
366  * @param connection the connection
367  * @returns the base service name
368  */
369 const char*
370 dbus_bus_get_base_service (DBusConnection *connection)
371 {
372   BusData *bd;
373
374   bd = ensure_bus_data (connection);
375   if (bd == NULL)
376     return NULL;
377   
378   return bd->base_service;
379 }
380
381 /**
382  * Asks the bus to try to acquire a certain service.
383  *
384  * @todo these docs are not complete, need to document the
385  * return value and flags
386  * 
387  * @todo if we get an error reply, it has to be converted into
388  * DBusError and returned
389  *
390  * @param connection the connection
391  * @param service_name the service name
392  * @param flags flags
393  * @param error location to store the error
394  * @returns a result code, -1 if error is set
395  */ 
396 int
397 dbus_bus_acquire_service (DBusConnection *connection,
398                           const char     *service_name,
399                           unsigned int    flags,
400                           DBusError      *error)
401 {
402   DBusMessage *message, *reply;
403   int service_result;
404   
405   message = dbus_message_new (DBUS_SERVICE_DBUS,
406                               DBUS_MESSAGE_ACQUIRE_SERVICE);
407
408   if (message == NULL)
409     {
410       _DBUS_SET_OOM (error);
411       return -1;
412     }
413  
414   if (!dbus_message_append_args (message,
415                                  DBUS_TYPE_STRING, service_name,
416                                  DBUS_TYPE_UINT32, flags,
417                                  0))
418     {
419       dbus_message_unref (message);
420       _DBUS_SET_OOM (error);
421       return -1;
422     }
423   
424   reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
425                                                      error);
426   
427   dbus_message_unref (message);
428   
429   if (reply == NULL)
430     {
431       _DBUS_ASSERT_ERROR_IS_SET (error);
432       return -1;
433     }
434
435   if (!dbus_message_get_args (reply, error,
436                               DBUS_TYPE_UINT32, &service_result,
437                               0))
438     {
439       _DBUS_ASSERT_ERROR_IS_SET (error);
440       return -1;
441     }
442
443   return service_result;
444 }
445
446 /**
447  * Checks whether a certain service exists.
448  *
449  * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
450  *
451  * @param connection the connection
452  * @param service_name the service name
453  * @param error location to store any errors
454  * @returns #TRUE if the service exists, #FALSE if not or on error
455  */
456 dbus_bool_t
457 dbus_bus_service_exists (DBusConnection *connection,
458                          const char     *service_name,
459                          DBusError      *error)
460 {
461   DBusMessage *message, *reply;
462   unsigned int exists;
463
464   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
465   
466   message = dbus_message_new (DBUS_SERVICE_DBUS,
467                               DBUS_MESSAGE_SERVICE_EXISTS);
468   if (message == NULL)
469     {
470       _DBUS_SET_OOM (error);
471       return FALSE;
472     }
473   
474   if (!dbus_message_append_args (message,
475                                  DBUS_TYPE_STRING, service_name,
476                                  0))
477     {
478       dbus_message_unref (message);
479       _DBUS_SET_OOM (error);
480       return FALSE;
481     }
482   
483   reply = dbus_connection_send_with_reply_and_block (connection, message, -1, error);
484   dbus_message_unref (message);
485
486   if (reply == NULL)
487     {
488       _DBUS_ASSERT_ERROR_IS_SET (error);
489       return FALSE;
490     }
491
492   if (!dbus_message_get_args (reply, error,
493                               DBUS_TYPE_UINT32, &exists,
494                               0))
495     {
496       _DBUS_ASSERT_ERROR_IS_SET (error);
497       return FALSE;
498     }
499   
500   return (exists != FALSE);
501 }
502
503 /** @} */